C++:构造函数与析构函数

一.类的默认成员函数

默认成员函数就是用户没有显式实现,编译器会自动生成的成员函数称为默认成员函数,如下图:

 其中最重要的就是我们表格中的前四个函数,本篇文章我们主要介绍前三个。默认成员函数很重要,也比较复杂,我们要从两个方面去学习:

1.我们不写时,编译器默认生成的函数行为是什么,是否满足我们的需求。

2.编译器默认生成的函数不满足我们的需求,我们需要自己实现,那么如何自己实现

二.构造函数

首先我们需要注意的是,构造函数名不如其名,他并不是不是开空间创建对象,而是对象实例化时初始化对象。构造函数的本质是要替代我们以前Stack和Date类中写的Init函数的功能,构造函数自动调用的特点就完美的替代的了Init。

构造函数的性质与特点
1. 函数名与类名相同

比如我们要写一个栈,一个简单的例子如下:

class Stack
{
public:Stack(){top = 0;capacity = 4;int* top1 = (int*)realloc(arr, 4 * sizeof(int));if (top1 == nullptr){perror("fail realloc arr");return;}arr = top1;}private:int* arr;int top;int capacity;
};

这时当我们去创建一个新的栈时编译器便会自动的去调用我们写的构造函数完成我们栈的初始化。 

2. 无返回值。 (返回值啥都不需要给,也不需要写void,不要纠结,C++规定如此)

3. 对象实例化时系统会自动调用对应的构造函数。

比如我们使用上面1中的类去创建一个d1的栈,在创建时d1便会自动初始化:

4. 构造函数可以重载。

5. 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成。

当我们不在显示定义我们的构造函数时,初始化的结果由编译器决定:

这里使用的是vs2022,所以当我们需要进行初始化的时候,尽量自己写构造函数。

6. 无参构造函数、全缺省构造函数、我们不写构造时编译器默认生成的构造函数,都叫做默认构造函数。但是这三个函数有且只有一个存在,不能同时存在。无参构造函数和全缺省构造函数虽然构成函数重载,但是调用时会存在歧义。要注意很多人会认为默认构造函数是编译器默认生成那个叫默认构造,实际上无参构造函数、全缺省构造函数也是默认构造,总结一下就是不传实参就可以调用的构造就叫默认构造。

产生歧义这一点因为一个是无参,而另一个是全缺省,当我们不去传任何参数的时去初始化类对象时,编译器便会不知道去调用哪一个,从而产生歧义。

7.当我们不写构造函数的时候,编译器只会初始化成员中属于内置类型的数据,int,char,double等等。如果说在我们的成员对象中有自定义对象时,而我们没有写构造函数,那编译器就会直接报错。如果我们想要初始化这个成员变量,则需要用到我们之后介绍的初始化列表,这里我们暂时先不介绍。

三.析构函数

这里的析构函数与我们的构造函数的功能恰恰相反,一般我们是用它来进行类对象的销毁工作。但当然我们也可以不局限与这点,可以把对象收尾时需要进行的函数放在我们的析构函数中。

析构函数的特点

1. 析构函数名是在类名前加上字符 ~。

比如Stack:

~Stack()
{}

2. 无参数无返回值。 (这里跟构造类似,也不需要加void)

3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。

4. 对象生命周期结束时,系统会自动调用析构函数。

5. 跟构造函数类似,我们不写编译器自动生成的析构函数对内置类型成员不做处理,自定类型成员会调用他的析构函数。

6. 还需要注意的是我们显示写析构函数,对于自定义类型成员也会调用他的析构,也就是说自定义类型成员无论什么情况都会自动调用析构函数。

7. 如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数。但是有资源申请时,除了某些情况,一定要自己写析构,否则会造成资源泄漏。

这里某些情况我们举个栗子,比如我们在写用两个栈去实现队列的时候,我们的成员如下:

class Myqueen
{
public:Myqueen(){//初始化函数}//..........
private:Stack d1;Stack d2;
};

 这种情况下就不需要我们自己去写析构函数了,因为我们在类对象的销毁时也会调用自定义类型的析构函数(不过我们Stack的析构函数还是要写的)。

8.一个局部域的多个对象,C++规定后定义的先析构。

我们举个例子:

Stack A;
int main()
{Stack B;Stack C;static Stack D;return 0;
}

这里我们的析构函数的调用顺序是CBDA,BC由我们上面定义即可轻松判断出顺序,而D为静态对象,与A全局对象的生命周期是一致的,而D又比A后定义,所以调用析构函数的顺序则是CBDA。 

四. 拷贝构造函数

拷贝构造函数其实是在我们传参的时候需要进行调用的,它的基本形式为(我们以Stack为例):

Stack(Stack& d);

拷贝构造的调用形式如下:

Stack d1;
Stack d2(d1);
//或者可以这样拷贝构造:Stack d2 = d1;

正如我们的自定义类型成员需要对应的初始化构造函数一样,对与我们的内置类型进行传参的时不需要拷贝构造函数,而自定义类型在进行传参的时候则需要对应的拷贝构造函数 。

拷贝构造函数的特点:

1. 拷贝构造函数是构造函数的一个重载。

2. 拷贝构造函数的第一个参数必须是类类型对象的引用,使用传值方式编译器直接报错,因为语法逻辑上会引发无穷递归调用。 拷贝构造函数也可以多个参数,但是第一个参数必须是类类型对象的引用,后面的参数必须有缺省值。

比如我们下面的例子:

当我们在进行函数的调用的时候,func函数会先去找d1的拷贝构造函数,这时如果没有拷贝构造,便会去使用我们下面图的函数,这时发现传值的对象为自定义类型,那么便会继续去找它的拷贝构造函数,这是C++的规定,接下来找不到在第三幅图中再次调用,又去找他的拷贝函数,最终形成了无限循环。(当然实际情况下编译器会直接报错,不会去进行所谓的无限递归,同时补充一点,第三幅图的realloc最好替换为malloc)。

3. C++规定自定义类型对象进行拷贝行为必须调用拷贝构造,所以这里自定义类型传值传参和传值返回都会调用拷贝构造完成。

4. 若未显式定义拷贝构造,编译器会生成自动生成拷贝构造函数。自动生成的拷贝构造对内置类型成员变量会完成值拷贝/浅拷贝(一个字节一个字节的拷贝),对自定义类型成员变量会调用他的拷贝构造。

当我们不显示定义拷贝构造的时候,我们会发现虽然好像拷贝的一模一样,比如Stack,我们先定义一个D1,再用D2拷贝复制D1。我们会发现报错,这是因为析构函数的特性,你的D2与D1arr指向的空间一模一样,所以D2释放后D1再去释放便会报错。

5. 如果类成员变量全是内置类型且没有指向什么资源,编译器自动生成的拷贝构造就可以完成需要的拷贝,所以不需要我们显示实现拷贝构造。像Stack这样的类,虽然也都是内置类型,但是_a指向了资源,编译器自动生成的拷贝构造完成的值拷贝/浅拷贝不符合我们的需求,所以需要我们自己实现深拷贝(对指向的资源也进行拷贝)。像MyQueue这样的类型内部主要是自定义类型Stack成员,编译器自动生成的拷贝构造会调用Stack的拷贝构造,也不需要我们显示实现MyQueue的拷贝构造。这里还有一个小技巧,如果一个类显示实现了析构并释放资源,那么他就需要显示写拷贝构造,否则就不需要。

6. 传值返回会产生一个临时对象调用拷贝构造,传值引用返回,返回的是返回对象的别名(引用),没有产生拷贝。但是如果返回对象是一个当前函数局部域的局部对象,函数结束就销毁了,那么使用引用返回是有问题的,这时的引用相当于一个野引用,类似一个野指针一样。传引用返回可以减少拷贝,但是一定要确保返回对象,在当前函数结束后还在,才能用引用返回。这样其实相当与一种权限的放大。

博主的介绍比较粗浅,如有错误尽情谅解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/415271.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

下载xhsell连接Linux系统

一、下载安装xshell 1、下载 免费版的网址:家庭/学校免费 - NetSarang Website 2、安装 选择自己想要下载的文件夹位置 创建一个新的文件夹即可 不想注册可以直接选择后来先进行试用 二、连接Linux虚拟机 1、点击加号新建会话 2、输入你要连接的虚拟机的IP地址…

4、Django Admin对自定义的计算字段进行排序

通常,Django会为模型属性字段,自动添加排序功能。当你添加计算字段时,Django不知道如何执行order_by,因此它不会在该字段上添加排序功能。 如果要在计算字段上添加排序,则必须告诉Django需要排序的内容。你可以通过在…

【综合架构】Part 5.2 Ansible

使用设备:管理设备-m01-10.0.0.61 1 概述 自动化运维工具:可实现批量管理、批量分发、批量执行、维护... Ansible 是由 Python语言 所编写 2 管理架构 Inventory 主机清单:被管理主机的ip列表、分类。ad-hoc模式:命令行批量管理…

迁移学习之领域偏移(domain shift)

实际应用中很多任务的数据的标注成本很高,无法获得充足的训练数据,这种情况可以 使用迁移学习(transfer learning)。假设 A、B 是两个相关的任务,A 任务有很多训练数 据,就可以把从A任务中学习到的某些可以泛化知识迁移…

《信息技术 云计算 边缘云通用技术要求》国家标准发布,九州未来参编

日前,2024年第17号国家标准公告发布,由全国信标委云计算标准工作组组织制定、九州未来作为行业专家单位参编的《信息技术 云计算 边缘云通用技术要求》国家标准正式获批发布。 边缘云作为云计算技术的有效补充和拓展,能够实现将云计算能力拓展…

java常用类

目录 1 String类 1字符串的构造方法: 2.常量池 3 .字符串的比较 1 equals 2 equalsIgnorecase 3.字符串长度: 4.拼接字符串 5.获取单个字符: 6.子字符串的索引(首个) 7.截取字符串 8.将String的转换为数组&…

设计模式 -- 迭代器模式(Iterator Pattern)

1 问题引出 编写程序展示一个学校院系结构:需求是这样,要在一个页面中展示出学校的院系组成,一个学校有多个学院, 一个学院有多个系 传统方式实现 将学院看做是学校的子类,系是学院的子类,这样实际上是站在…

服务器数据恢复—如何应对双循环RAID5阵列的数据丢失问题?

服务器存储数据恢复环境: 一台存储中有一组由7块硬盘组建的RAID5阵列,存储中还有另外3块盘是raid中掉线的硬盘(硬盘掉线了,管理员只是添加一块的新的硬盘做rebuild,并没有将掉线的硬盘拔掉)。整个RAID5阵列…

F12控制台输入警告?

信息如下: Warning: Don’t paste code into the DevTools Console that you don’t understand or haven’t reviewed yourself. This could allow attackers to steal your identity or take control of your computer. Please type ‘allow pasting’ below and …

Type-C接口诱骗取电快充方案

Type-C XSP08Q 快充协议芯片是一种新型电源管理芯片,主要负责控制充电电流和电压等相关参数,从而实现快速充电功能。Type-C XSP08Q快充协议是在Type-C接口基础上,加入了XSP08Q协议芯片的支持,很大程度上提升了充电速度。 正常情况…

css实现卡片右上角的状态

1、成品展示 2、html部分 <div class"itemBox"><div class"status">{{ statusList[item.status] }}</div> </div> 3、css部分 .itemBox {position: relative;overflow: hidden; } .status {height: 25px;line-height: 25px;bac…

【实战教程】用 Next.js 和 shadcn-ui 打造现代博客平台

你是否梦想过拥有一个独特、现代化的个人博客平台&#xff1f;今天&#xff0c;我们将一起动手&#xff0c;使用 Next.js 和 shadcn-ui 来创建一个功能丰富、外观精美的博客系统。无论你是刚接触 Web 开发&#xff0c;还是经验丰富的程序员&#xff0c;这个教程都将带你step by…

Linux网络编程 --- Socket编程

前言 首先看看TCP/IP网络协议和在我们计算机系统层次中的对应关系。 socket的位置 网络通信的本质就是贯穿网络协议层的过程。 局域网数据的封装和解包过程 逻辑上我们认为同层协议之间通信 几乎任何层的协议都会提供一种解包和分用的功能。 几乎任何层的协议&#xff…

FPGA实现SDI视频H265压缩网络推流输出,基于VCU架构,支持12G-SDI 4K60帧,提供工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐我这里已有的视频图像编解码方案本博已有的 SDI 编解码方案 3、详细设计方案设计框图FPGA开发板视频输入SDI硬件均衡器LMH1219UHD-SDI GT SDI视频解串SMPTE UHD-SDI RX SUBSYSTEM SDI视频解码Video Frame Buffer WriteZynq UltraS…

Apollo Planning模块中的Hybird A*算法

文章目录 流程图OpenSpacePlanner算法与周边模块关系OpenSpacePlanner与PublicRoadPlanner关系Hybird A*流程Hybird A*外部调用入口Hybird A*内部流程 Hybird A*代码逻辑主函数Plan碰撞检测ReedsShepp曲线加速搜索扩展相邻的节点计算节点的代价路径后处理路径分割轨迹平滑&…

android AccessibilityService合法合规增加小红书曝光阅读量(2024-09-02)

免责任声明: 任何可操作性的内容与本人无关,文章内容仅供参考学习&#xff0c;如有侵权损害贵公司利益&#xff0c;请联系作者&#xff0c;会立刻马上进行删除。 一、分析 目前可增加曝光阅读流量渠道入口&#xff08;完成&#xff09; 1. 发现页 打开小红书app选择顶部发现页&…

【网络世界】网络层

目录 &#x1f308;前言&#x1f308; &#x1f4c1; 网络层 &#x1f4c1; IPV4 &#x1f4c2; 什么是IP地址 &#x1f4c2; 网段划分 &#x1f4c2; 特殊IP &#x1f4c2; 内网和公网 &#x1f4c2; IPV4的危机 &#x1f4c1; IP协议格式 &#x1f4c1; 路由 &#x1f…

VSCode+Keil协同开发之Keil Assistant

VSCodeKeil协同开发之Keil Assistant 目录 VSCodeKeil协同开发之Keil Assistant1. 效果展示2. Keil Assistant简介3. Keil Assistant功能特性4. 部署步骤4.1. 部署准备4.2. 安装Keil Assistant插件4.3. 配置Keil Assistant插件 5. Keil Assistant使用6. 总结 大家在单片机开发时…

密码学基础

一、理论知识 科尔霍夫原则 1、对于一个密码学系统&#xff0c;应当仅有密钥是保密的&#xff0c;其余算法和一切参数都应该是公开的 2、并不一定要数学上完全不可破解&#xff0c;只要在现实中不可能破解即可 对称加密 加密解密都使用相同的密钥 非对称加密 1、加密解密…

【iOS】通过第三方库Masonry实现自动布局

目录 前言 约束 添加约束的规则 使用Masonry自动布局 Masonry的常见使用方法 补充 前言 在暑期完成项目时&#xff0c;经常要花很多时间在调试各种控件的位置上&#xff0c;因为每一个控件的位置都需要手动去计算&#xff0c;在遇到循环布局的控件时&#xff0c;还需要设…