当前位置: 首页 > news >正文

从0开始C++(三):构造函数与析构函数详解

目录

构造函数 

构造函数的基本使用

构造函数也支持函数重载

构造函数也支持函数参数默认值

构造初始化列表

拷贝构造函数

浅拷贝和深拷贝

析构函数

 总结

练习一下ヽ( ̄▽ ̄)ノ 


构造函数 

构造函数的基本使用

构造函数是一种特殊的成员函数,用于创建对象时初始化,写法上有以下要求:

● 函数名称必须与类名完全一样。

● 构造函数不写返回值

● 如果程序员不手动编写构造函数,编译器就会自动添加一个默认无参数的构造函数。

● 手动添加构造函数后,编译器就不会自动添加默认无参构造函数。

class Car
{
private://权限:最私有的权限string brand;   // 品牌string modle;   // 型号int weight;     // 重量
public: // 权限:最开放的权限Car(string b,string m,int w) //手动添加的构造函数{brand=b;modle=m;weight=w;}string get_brand()   //外部函数接口{return brand;}string get_modle(){return modle;}int get_weight(){return weight;} 
};
int main()
{Car *myCar = new Car; //  创建堆内存对象//cout << Car.brand << endl;  //错误,brand是私有成员 不能外部访问cont << Car.get_brand << endl; //可以使用预留的接口访问 
}

构造函数也支持函数重载

class Car
{
private://权限:最私有的权限string brand;   // 品牌string modle;   // 型号int weight;     // 重量
public: // 权限:最开放的权限Car(string b,string m,int w) // 有参构造函数{brand=b;modle=m;weight=w;}Car()    // 无参构造函数{brand="xiaomi";modle="su7";weight=1500;}string get_brand()   // 外部函数接口{return brand;}string get_modle(){return modle;}int get_weight(){return weight;} 
};
int main()
{Car *myCar = new Car; //  调用无参构造函数Car *myCar2 = new Car("HuaWei","问界","2000"); // 此时调用有参构造函数}

构造函数也支持函数参数默认值

从第一个设置默认值的变量开始,在其变量之后的所有参数都要加默认值,在他之前的变量可以不加默认值。

class Car
{
private://权限:最私有的权限string brand;   // 品牌string modle;   // 型号int weight;     // 重量
public: // 权限:最开放的权限Car(string b="xiaomi",string m="su7",int w=1500) // 全缺省时,不能和无参构造函数同时存在{brand=b;modle=m;weight=w;}//    Car()    // 无参构造函数//    {//        brand="xiaomi";//        modle="su7";//       weight=1500;//    }string get_brand()   // 外部函数接口{return brand;}string get_modle(){return modle;}int get_weight(){return weight;} 
};
int main()
{Car *myCar = new Car; //  全缺省Car *myCar2 = new Car("问界","M7","2000"); // 此时调用有参构造函数}

构造初始化列表

当构造函数的局部变量与成员变量重名时可以使用构造初始列表的方式区分,此外,使用构造初始化列表还可以给被 const 修饰的成员变量赋值。

class Car
{
private://权限:最私有的权限const string brand;   // 品牌string modle;   // 型号int weight;     // 重量
public: // 权限:最开放的权限Car(string b,string modle,int w):brand(b),modle(modle),weight(w){} // 用构造初始化列表的方式赋值string get_brand()   // 外部函数接口{return brand;}string get_modle(){return modle;}int get_weight(){return weight;} 
};
int main()
{Car *myCar = new Car("问界","M7","2000"); // 此时调用有参构造函数}

拷贝构造函数

C++的拷贝构造函数是一种特殊的成员函数,用于创建一个对象的副本。它的参数是一个对象的引用,通过这个参数可以将一个对象的值复制给另一个对象。

拷贝构造函数通常在以下情况下被调用:

1、当用一个对象初始化另一个对象时,会调用拷贝构造函数。例如:

class MyClass {
public:MyClass(const MyClass& obj) {// 拷贝构造函数的实现}
};MyClass obj1;
MyClass obj2 = obj1;  // 调用拷贝构造函数

 2、当将一个对象作为函数参数传递给函数时,会调用拷贝构造函数。例如:

void func(MyClass obj) {// 函数体
}MyClass obj;
func(obj);  // 调用拷贝构造函数

3、当函数返回一个对象时,会调用拷贝构造函数。例如:

MyClass func() {MyClass obj;// 对 obj 进行初始化和操作return obj;  // 调用拷贝构造函数
}

需要注意的是,默认情况下,C++会生成一个默认的拷贝构造函数,该函数会将对象的所有成员变量进行一一拷贝。但如果类中存在指针或其他资源,需要手动编写拷贝构造函数来处理这些资源的拷贝问题,以防止浅拷贝带来的问题。

浅拷贝和深拷贝

C++中的拷贝操作有浅拷贝和深拷贝两种方式。

浅拷贝是指拷贝对象时,只是简单地将一个对象的数据成员的值复制给另一个对象的对应数据成员,而不会复制指向动态分配内存的指针。这意味着两个指针将指向同一块内存,当其中一个对象释放这块内存时,另一个对象的指针将成为悬空指针。例如:

class MyClass {
public:int* data;MyClass(const MyClass& other) : data(other.data) {// 拷贝构造函数的实现}
};MyClass obj1;
obj1.data = new int(5);MyClass obj2 = obj1;  // 浅拷贝delete obj1.data;  // 释放内存
cout << *obj2.data;  // 可能会输出无效的值

深拷贝是指拷贝对象时,除了复制数据成员的值外,还会为每个指针成员分配一块新的内存,并将源对象的值复制到新的内存中,以确保两个对象之间的指针成员指向不同的内存块。这样即使一个对象释放了内存,另一个对象的指针仍然有效。例如:

class MyClass {
public:int* data;MyClass(const MyClass& other) : data(new int(*other.data)) {// 拷贝构造函数的实现}~MyClass() {delete data;}
};MyClass obj1;
obj1.data = new int(5);MyClass obj2 = obj1;  // 深拷贝delete obj1.data;  // 释放内存
cout << *obj2.data;  // 仍然可以正常输出

析构函数

C++中的析构函数是一种特殊的成员函数,用于在对象的生命周期结束时执行清理操作。析构函数的名称与类的名称相同,前面加上一个波浪号(~)作为前缀,没有返回类型,也没有参数。

析构函数在以下情况下被调用:

  1. 当对象的作用域结束时,例如,当对象在函数中定义并在函数结束时销毁。
  2. 当对象是另一个对象的成员,并且该对象的析构函数被调用时。
  3. 当使用delete关键字显式释放通过new关键字配分的内存时。

析构函数的主要目的是释放对象分配的资源,例如动态分配的内存、打开的文件等。它可以通过在析构函数中使用delete关键字来释放内存,或者通过关闭文件句柄等操作来释放资源。

以下是一个示例,展示了一个类的析构函数的基本用法:

class MyClass {
public:MyClass() {cout << "构造函数被调用" << endl;}~MyClass() {cout << "析构函数被调用" << endl;}
};int main() {MyClass obj;  // 创建一个对象// 在此处执行其他操作return 0;  // 对象的作用域结束,析构函数被调用
}

当对象的作用域结束时,析构函数将被自动调用,输出如下结果:

构造函数被调用
析构函数被调用

需要注意的是,如果类中使用了动态分配的内存或其他资源,在析构函数中应该对这些资源进行释放,以避免内存泄漏或资源泄漏的问题。

 总结

构造函数

析构函数

创建对象时手动调用

当对象销毁时,自动调用

函数名称是类名

函数名称是~类名

构造函数可以重载

析构函数没有参数,不能重载

用于创建对象时并初始化

用于销毁对象时释放资源

有返回值但是不写,返回值是新创建的对象

没有返回值

练习一下ヽ( ̄▽ ̄)ノ 

写一个Dog类,要求有性别、年龄和品种三个属性,属性值封装,使用构造函数传参初始化。增加函数Dog* birth(const Dog& d),在函数体内部判断d与当前狗对象的属性值,当满足以下条件时,返回新创建的狗对象:

● 两条狗的年龄2-5

● 一公一母

新创建的狗对象的属性满足以下条件:

● 年龄:1岁

● 性别:随意

● 品种:

○ 如果父母的品种一样,品种就是父母的品种

○ 如果父母的品种不一样,品种是父母品种的拼合(自己制定拼合逻辑,或者直接是父母的品种之一)

如果两条狗不能生育,返回NULL。

参考代码

#include <iostream>
#include<string.h>
#include<time.h>
using namespace std;class Dog
{
private:int sex;  //0母 1公int age;  //小于2或大于5不能生育char *variety=new char[20];public:Dog(int s,int a,char *v){if(s==3) //  性别随机{sex=time(NULL)%2;}else{sex=s;}age=a;strcpy(variety,v);}Dog* brith(const Dog &D){if(sex != D.sex){if( age < 2 || age > 5 || D.age < 2 || D.age > 5 ){return NULL;}Dog* NewDog = new Dog(3,1,D.variety);return NewDog;}return NULL;}int get_sex(){return sex;}int get_age(){return age;}char *get_variety(){return variety;}};int main()
{int sex,age;char variety[20];while(1){cout << "请输入狗A的 性别(0:母 1:公) 年龄 品种" << endl;cin >> sex >> age >> variety;Dog dogA(sex,age,variety);cout << "请输入狗B的 性别(0:母 1:公) 年龄 品种" << endl;cin >> sex >> age >> variety;Dog dogB(sex,age,variety);Dog* NewDog=dogB.brith(dogA);if(NewDog==NULL){cout << "dogA和dogB无法生育" << endl;continue;}cout << "小狗的属性:" << endl;cout << "sex:" << NewDog->get_sex() << endl;cout << "age:" << NewDog->get_age() << endl;cout << "variety:" << NewDog->get_variety() << endl;}return 0;
}

相关文章:

从0开始C++(三):构造函数与析构函数详解

目录 构造函数 构造函数的基本使用 构造函数也支持函数重载 构造函数也支持函数参数默认值 构造初始化列表 拷贝构造函数 浅拷贝和深拷贝 析构函数 总结 练习一下ヽ(&#xffe3;▽&#xffe3;)&#xff89; 构造函数 构造函数的基本使用 构造函数是一种特殊的成…...

行车记录仪文件夹“0字节”现象解析与恢复策略

一、行车记录仪文件夹“0字节”现象描述 行车记录仪作为现代驾驶中的必备设备&#xff0c;其储存的视频数据对于事故记录和取证至关重要。然而&#xff0c;有时车主们可能会遇到这样一个问题&#xff1a;行车记录仪的某个文件夹内的文件突然变成了0字节大小&#xff0c;无法正…...

呼叫中心系统的功能都有哪些?okcc呼叫中心pscc磐石云呼叫系统部署

当前电话营销普及到各行各业&#xff0c;方便快捷成了大部分企业在宣传自己公司的产品时必用的一种营销方式&#xff0c;但是电话营销在管理上也存在许多问题。例如&#xff1a;销售员与客户沟通前&#xff0c;未能详细了解客户的资料&#xff1b;多名销售员重复拨打同一个客户…...

2024.06.08校招 实习 内推 面经

绿*泡*泡VX&#xff1a; neituijunsir 交流*裙 &#xff0c;内推/实习/校招汇总表格 1、提前批 | 中电锦江2025届提前批招聘 提前批 | 中电锦江2025届提前批招聘 2、实习 | 国电电力2025届暑期实习生计划启动&#xff01; 实习 | 国电电力2025届暑期实习生计划启动&#x…...

Polyplus——转染试剂专业供应商

PolyPlus-transfection是一家专业的转染试剂研发和生产的生物技术公司&#xff0c;拥有20年的的转染试剂研发经验&#xff0c;通过创新的核酸转染解决方案支持基因和细胞治疗、生物制剂制造和生命科学研究。目前已经通过了ISO 9001: 2000质量体系认证&#xff0c;已经开发了一系…...

微服务架构-线上治理、线下治理与架构演进

目录 一、线上治理 1.1 概述 1.2 线上预案体系 1.2.1 概述 1.2.2 变更引起的故障 1.2.3 流量和容量变化引起的故障 1.2.4 依赖故障 1.2.5 机房、网络等硬件和环境故障 1.2.6 其他 1.2.7 故障的场景化 1.3 基于Metric的预案自动触发 1.4 治理参数动态调整 1.4.1 举例…...

网络安全:什么是SQL注入

文章目录 网络安全&#xff1a;什么是SQL注入引言SQL注入简介工作原理示例代码 攻击类型为什么SQL注入危险结语 网络安全&#xff1a;什么是SQL注入 引言 在数字化时代&#xff0c;数据安全成为了企业和个人最关心的问题之一。SQL注入&#xff08;SQL Injection&#xff09;是…...

从零开始精通Onvif之网络配置

&#x1f4a1; 如果想阅读最新的文章&#xff0c;或者有技术问题需要交流和沟通&#xff0c;可搜索并关注微信公众号“希望睿智”。 概述 网络配置是Onvif规范中的重要组成部分&#xff0c;允许用户通过网络远程配置和管理设备的网络设置&#xff0c;比如&#xff1a;DHCP、IP地…...

在 macOS 上使用 Homebrew 安装和配置 Python 及 Tk 库

在 macOS 上&#xff0c;系统自带的 /usr/bin/python3 版本较旧&#xff0c;且直接升级系统自带的 Python 版本可能会影响系统稳定性。因此&#xff0c;推荐使用 Homebrew 来安装和管理 Python 及其相关库。本文将详细介绍如何通过 Homebrew 安装和配置 Python 3 及 Tk 库&…...

【机器学习 复习】第2章 线性回归及最大熵模型

一、概念 1.回归就是用一条曲线对数据点进行拟合&#xff0c;该曲线称为最佳拟合曲线&#xff0c;这个拟合过程称为回归。 2.一个自变量 叫 一元线性回归&#xff0c;大于一个自变量 叫 多元线性回归。 &#xff08;1&#xff09;多元回归&#xff1a;两个x&#xff0c;一个…...

关于椭圆的方程(有Python画的动图)

关于椭圆的方程&#xff08;有Python画的动图&#xff09; flyfish 几何定义 椭圆是平面上所有到两个固定点&#xff08;焦点&#xff09;的距离之和为常数的点的集合。这两个固定点叫做焦点。 解析几何描述 设椭圆的两个焦点为 F 1 F_1 F1​ 和 F 2 F_2 F2​&#xff…...

selenium常见难点解决方案

勾选框勾选问题 勾选框代码逻辑实现过程&#xff1a; 第一步&#xff1a;首先找到勾选框的元素&#xff1b; 第二步&#xff1a;检查它是否已经被勾选。如果已经勾选&#xff0c;则进行取消勾选操作&#xff1b;如果未勾选&#xff0c;则进行点击勾选操作&#xff1b; 以下是一…...

【Python高级编程】 综合练习-使用OpenCV 进行视频数据处理

综合练习 读取一个视频文件&#xff0c;对其进行处理后保存为一个新的视频文件。具体的处理步骤包括调整帧大小、转换为灰度图像、垂直翻转画面以及添加高斯噪声。 下面是代码的详细实现&#xff1a; import cv2 import numpy as np# 定义一个函数&#xff0c;用来给图像添加…...

rs232和can的区别

在电机通讯和升级固件时我们经常用到RS232和CAN两种通讯模式&#xff0c;那这两种有何不同吗&#xff1f; RS232和CAN的主要区别在于通信方式、应用场景、传输距离、通信速度以及网络结构。 通信方式&#xff1a; RS232是一种串行通信接口标准&#xff0c;支持全双工通信&…...

嵌入式软件stm32面试

一、STM32的内核型号有哪些&#xff1f; STM32系列是STMicroelectronics&#xff08;意法半导体&#xff09;生产的基于ARM Cortex-M内核的微控制器产品线。这些产品按照不同的内核架构和性能特点分为了主流产品、超低功耗产品和高性能产品。 1.1 主流产品 STM32F0 系列&…...

【Git】-- 添加公钥到 github 或者gitlab上

仅针对系统&#xff1a;mac os 、 unix、linux 1、检查是否有 id_rsa.pub $ cd ~ $ ls -al ~/.ssh 注意&#xff1a;若已有 id_rsa.pub&#xff0c;则必要执行 第二步&#xff0c;避免覆盖掉原有正常的公钥。 配置多个 git 账号请参考&#xff1a;同一台电脑配置多个git账…...

Vue页面生成PDF后调起浏览器打印

一、安装依赖 首先&#xff0c;需要安装 html2canvas 和 jsPDF 库。 npm install html2canvas jspdf二、创建公共方法引入 在utils文件夹下创建两个文件分别为pdfExport.js和printPDF.js&#xff0c;代码如下&#xff1a; pdfExport.js import html2canvas from html2canv…...

纯前端实现导出excel

项目背景&#xff1a; vue2 插件&#xff1a; xlsx&#xff1b;xlsx-style&#xff1b;file-saver 说明&#xff1a; 单独使用 xlsx插件&#xff0c;也可以将网页上的table导出成excel&#xff0c;但是导出的excel&#xff0c;没有样式 结合xlsx-style&#xff1b;file-saver&a…...

QT windows 5.12.0 安装包

这个是在线包&#xff0c;需要有账号的。 没有也没事&#xff0c;安装界面可以现场注册 百度网盘链接&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1QvXDert4b94GbUfD2f2G4g?pwd8888 提取码&#xff1a;8888...

改进YOLOv7 | 在 ELAN 模块中添加【Triplet】【SpatialGroupEnhance】【NAM】【S2】注意力机制 | 附详细结构图

改进 YOLOv7 | 在 ELAN 模块中添加【Triplet】【SpatialGroupEnhance】【NAM】【S2】注意力机制&#xff1a;中文详解 1. 简介 YOLOv7 是目前主流的目标检测算法之一&#xff0c;具有速度快、精度高的特点。但 YOLOv7 的原始模型结构中缺乏注意力机制&#xff0c;导致模型对全…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

python打卡day49

知识点回顾&#xff1a; 通道注意力模块复习空间注意力模块CBAM的定义 作业&#xff1a;尝试对今天的模型检查参数数目&#xff0c;并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

黑马Mybatis

Mybatis 表现层&#xff1a;页面展示 业务层&#xff1a;逻辑处理 持久层&#xff1a;持久数据化保存 在这里插入图片描述 Mybatis快速入门 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6501c2109c4442118ceb6014725e48e4.png //logback.xml <?xml ver…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile&#xff0c;新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...