【C++】构造函数和析构函数第三部分(各种构造函数调用规则、多个对象的构造和析构、初始化列表)--- 2023.11.6

目录

      • 各种构造函数的调用规则
        • 对象以值的方式给函数参数
        • 用一个已有的对象去初始化另一个对象
        • 函数的局部对象以值的方式从函数返回
        • 调用规则1
        • 调用规则2
      • 多个对象的构造和析构
      • 初始化列表
      • 结束语

各种构造函数的调用规则

对象以值的方式给函数参数

实例:

class Maker
{
public:Maker(){cout << "无参构造函数" << endl;}Maker(int a){cout << "有参构造函数" << endl;}Maker(const Maker &maker){cout << "拷贝构造函数" << endl;}~Maker(){cout << "析构函数" << endl;}
};void func(Maker m)
{}void test01()
{Maker m1;func(m1);}

对上述代码进行分析:

Maker m1;

实例化对象,并且该对象名为m1,在实例化对象过程中会调用Maker类中的无参构造。

func(m1);

该func函数中的形参为Maker m,并且传入该函数的形参为刚刚实例化完成的对象m1,所以实际上为Maker m = m1。即会调用Maker类中的拷贝构造函数。

最后在完成该函数生命周期时,会相反顺序依次调用析构函数来完成释放。

代码运行结果如下:

在这里插入图片描述

用一个已有的对象去初始化另一个对象

实例:

void test02()
{Maker m1;Maker m2(m1);
}

对上述代码进行分析:

Maker m1;

实例化对象,并且该对象名为m1,在实例化对象过程中会调用Maker类中的无参构造。

Maker m2(m1);

相当于调用Maker类中的拷贝构造函数。

代码运行结果如下:
在这里插入图片描述

函数的局部对象以值的方式从函数返回

实例:

Maker func2()
{//局部对象Maker m;cout << "局部对象的地址:" << &m << endl;return m;
}void test03()
{Maker m1 = func2();cout << "m1对象的地址:" << &m1 << endl;
}

对上述代码进行分析:

func2函数的主要作用为将实例化成功的对象m的地址打印出来,并且将该对象作为该函数的返回值。

Maker m1 = func2();

将func2()的函数的返回值传递给m1,并且打印m1的地址。理论上m1和m的地址是一样的。

代码运行结果如下:
在这里插入图片描述

调用规则1

如果程序员提供了有参构造,那么编译器不会提供默认构造函数,但是会提供默认的拷贝构造

实例:

class Maker
{
public:Maker(){cout << "无参构造函数" << endl;}Maker(int a){cout << "有参构造函数" << endl;}~Maker(){cout << "析构函数" << endl;}
};void test01()
{Maker m(10);Maker m2(m);
}

对上述代码进行分析:

Maker m(10);

调用Maker类中的有参构造函数,即a = 10

Maker m2(m);

使用该函数将会调用拷贝构造函数,但是我们发现在Maker类中并没有创建拷贝构造函数,我们先试试看程序能不能正常运行?

代码运行结果如下:
在这里插入图片描述
由上述可知,代码可以正常运行,并没有报错,这是因为编译器会提供默认的拷贝构造函数,只不过这个拷贝构造函数不做任何处理。

调用规则2

如果程序员提供了拷贝构造函数,那么编译器不会提供默认的构造函数和默认的拷贝构造函数

实例:

class Maker
{
public:Maker(const Maker& maker){cout << "拷贝构造函数" << endl;}~Maker(){cout << "析构函数" << endl;}
};void test02()
{Maker m;
}

对上述代码进行分析:

Maker m;

实例化对象m时,会自动调用构造函数,但是我们发现在Maker类中创建了拷贝构造函数,我们先试试看代码能不能正常运行?

代码运行结果如下:

在这里插入图片描述
从上可知,代码并不能正常运行,即我们可以得知,当提供了拷贝构造函数,那么编译器不会提供默认的构造函数和默认的拷贝构造函数。

多个对象的构造和析构

实例:

class BMW
{
public:BMW(){cout << "BMW构造" << endl;}~BMW(){cout << "BMW析构" << endl;}
};class Buick
{
public:Buick(){cout << "Buick构造" << endl;}~Buick(){cout << "Buick析构" << endl;}
};class Maker
{
public:Maker(){cout << "Maker构造" << endl;}~Maker(){cout << "Maker析构" << endl;}
private:Buick bui;//成员对象BMW bmw;//成员对象
};void test01()
{Maker m;
}

对上述代码进行分析:

private:Buick bui;BMW bmw;

在之前的实例中,我们一般私有化的时变量,并没有对对象进行私有化,但是实际上在C++中这个是可以私有化的,并且我们将该对象称为成员对象。

接下来我们先看看代码效果是什么样子的?

在这里插入图片描述

如上所示,首先会调用Buick构造函数,然后紧接着是BMW构造函数,最后才是Maker构造函数,细心的我们会发现如果类有成员对象,那么先调用成员对象的构造函数,再调用本身的构造函数,析构函数的调用顺序反之。

那么此时我们如果将Buick和BMW的顺序互换一下,代码运行效果会是什么呢?

代码运行结果如下:

在这里插入图片描述
并且还需要注意一点:

如果有成员对象,那么实例化对象时,必须保证成员对象的构造和析构能被调用

初始化列表

实例:

class BMW2
{
public:BMW2(int a){cout << "BMW2有参构造" << a << endl;}~BMW2(){cout << "BMW2析构" << endl;}
};class Buick2
{
public:Buick2(){cout << "Buick2构造" << endl;}~Buick2(){cout << "Buick2析构" << endl;}
};class Maker2
{
public:Maker2() :bmw(10){cout << "Maker2构造" << endl;}~Maker2(){cout << "Maker2析构" << endl;}
private:Buick2 bui;//成员对象BMW2 bmw;//成员对象
};void test02()
{Maker2 m;
}int main()
{test02();
}

对上述代码进行分析:

Maker2() :bmw(10){cout << "Maker2构造" << endl;}

当调用Maker2的构造函数时,会调用成员对象bmw的有参构造函数,并将10赋值给a。

代码运行结果如下:

在这里插入图片描述
那此时有多个对象需要指定调用某个构造函数,我们需要用逗号隔开。

实例如下:

class BMW2
{
public:BMW2(int a){cout << "BMW2有参构造" << a << endl;}~BMW2(){cout << "BMW2析构" << endl;}
};class Buick2
{
public:Buick2(int b, int c){cout << "Buick2构造" << endl;}~Buick2(){cout << "Buick2析构" << endl;}
};class Maker2
{
public:Maker2(int a, int b, int c) :bmw(a), bui(b, c){cout << "Maker2构造" << endl;}~Maker2(){cout << "Maker2析构" << endl;}
private:Buick2 bui;//成员对象BMW2 bmw;//成员对象
};void test02()
{Maker2 m(30, 10, 20);
}int main()
{test02();
}

对上述代码进行分析:

Maker2(int a, int b, int c) :bmw(a), bui(b, c)
{cout << "Maker2构造" << endl;
}

当使用Maker2进行实例化对象为m时,需要使用有参构造函数,将30,10,20这三个值分别传给bmw和bui对象,并且中间用逗号隔开。

代码运行结果如下:

在这里插入图片描述

除了以上几点,还有几点需要我们注意:

  1. 初始化列表是干什么用的,指定调用成员对象的某个构造函数
  2. 初始化列表只能写在构造函数
  3. 如果使用了初始化列表,那么所有的构造函数都要写初始化列表
  4. 可以使用对象的构造函数传递数值给成员对象的变量

结束语

如果觉得这篇文章还不错的话,记得点赞 ,支持下!!!

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

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

相关文章

Linux上编译sqlite3库出现undefined reference to `sqlite3_column_table_name‘

作者&#xff1a;朱金灿 来源&#xff1a;clever101的专栏 为什么大多数人学不会人工智能编程&#xff1f;>>> 在Ubuntu 18上编译sqlite3库后在运行程序时出现undefined reference to sqlite3_column_table_name’的错误。网上的说法是说缺少SQLITE_ENABLE_COLUMN_M…

libevent

libevent 库概念和特点 开源。精简。跨平台&#xff08;Windows、Linux、maxos、unix&#xff09;。专注于网络通信&#xff08;不一定非用在网络当中&#xff0c;比如下面的读写管道&#xff09;。 libevent特性&#xff1a;基于"事件"&#xff0c;面向“文件描述符…

软件开发项目文档系列之十如何撰写测试用例

目录 1 概述1.1 编写目的1.2 定义1.3 使用范围1.4 参考资料1.5 术语定义 2 测试用例2.1 功能测试2.1.1 用户登录功能2.1.2 商品搜索功能 2.2 性能测试2.2.1 网站响应时间2.2.2 并发用户测试 附件&#xff1a; 测试用例撰写的要素和注意事项附件1 测试用例要素附件2 测试用例的注…

【鸿蒙软件开发】ArkUI容器组件之Grid(网格布局)

文章目录 前言一、Grid1.1 子组件GridItem是什么子组件接口属性事件示例代码 1.2 接口参数 1.3 属性1.4 Grid的几种布局模式1.5 GridDirection枚举说明1.6事件ItemDragInfo对象说明 1.7 示例代码 总结 前言 Grid容器组件&#xff1a;网格容器&#xff0c;由“行”和“列”分割…

【数据结构初级(2)】单链表的基本操作和实现

文章目录 Ⅰ 概念及结构1. 单链表的概念2. 单链表的结构 Ⅱ 基本操作实现1. 定义单链表结点2. 创建新结点3. 单链表打印4. 单链表尾插5. 单链表头插6. 单链表尾删7. 单链表头删8. 单链表查找9. 在指定 pos 位置前插入结点10. 删除指定 pos 位置的结点11. 单链表销毁 本章实现的…

P02项目(学习)

★ P02项目 项目描述&#xff1a;安全操作项目旨在提高医疗设备的安全性&#xff0c;特别是在医生离开操作屏幕时&#xff0c;以减少非授权人员的误操作风险。为实现这一目标&#xff0c;我们采用多层次的保护措施&#xff0c;包括人脸识别、姿势检测以及二维码识别等技术。这些…

数据结构-邻接表广度优先搜索(C语言版)

对于一个有向图无向图&#xff0c;我们下面介绍第二种遍历方式。 广度优先搜索&#xff0c;即优先对同一层的顶点进行遍历。 如下图所示&#xff1a; 该例子&#xff0c;我们有六个顶点&#xff0c; 十条边。 对于广度优先搜索&#xff0c;我们先搜索a&#xff0c;再搜索abc…

5、Python中的变量和表达式:变量的定义、赋值和数据类型转换

文章目录 Python中的变量和表达式:变量的定义、赋值和数据类型转换变量的定义变量的赋值数据类型转换注意事项表达式总结Python中的变量和表达式:变量的定义、赋值和数据类型转换 Python是一种高级编程语言,以其简洁明了的语法和强大的功能而闻名。在Python编程中,变量和表…

力扣第121题 买卖股票的最佳时机 c++ 动态规划解法 熟练dp思维 之简单题 附Java代码

题目 &#xff08;在我以前有贪心解法&#xff0c;也可以去参考参考&#xff09; 贪心解法 股票问题https://blog.csdn.net/jgk666666/article/details/133978629 121. 买卖股票的最佳时机 简单 相关标签 数组 动态规划 给定一个数组 prices &#xff0c;它的第 i 个元…

NVMe FDP会被广泛使用吗?

文章开头&#xff0c;我们需要先了解固态硬盘的读写机制。我们知道&#xff0c;固态硬盘的存储单元是由闪存颗粒组成的&#xff0c;无法实现物理性的数据覆盖&#xff0c;只能擦除然后写入&#xff0c;重复这一过程。因而&#xff0c;我们可以想象得到&#xff0c;在实际读写过…

Mac VsCode g++编译报错:不支持C++11语法解决

编译运行时报错&#xff1a; [Running] cd “/Users/yiran/Documents/vs_projects/c/” && g 1116.cpp -o 1116 && "/Users/yiran/Documents/vs_projects/c/"1116 1116.cpp:28:22: warning: range-based for loop is a C11 extension [-Wc11-extensi…

Maven3.9.1安装及环境变量配置

一、Maven的下载与安装 maven各版本下载地址 打开链接后自行选择对应版本 下载完成后解压安装,最好别选择c盘,安装目录路径等使用英文,避免产生其他问题 我这里选择的是D盘 二、Maven的环境变量配置 2.1、右键点击此电脑选择属性&#xff0c;点击高级系统设置&#xff0c;点…

jenkins结合k8s部署动态slave

1、完成k8s连接 在完成jenkins的部署后现安装kubernets的插件 如果jenkins 是部署在k8s集群中只需要填写一下 如果是非本集群的部署则需要填写证书等 cat ./config echo ‘certificate-authority-data-value’ | base64 -d > ./ca.crt echo ‘client-certificate-data’ |…

结合组件库实现table组件树状数据的增删改

如图所示&#xff0c;可以实现树状数据的新增子项&#xff0c;新增平级&#xff0c;删除。主要用到了递归 代码&#xff1a; <template><el-table :data"tableData" style"width: 100%; margin-bottom: 20px" row-key"id" border def…

uniapp使用技巧及例子

前言 uniapp&#xff08;Universal Application&#xff09;是一种基于Vue.js的全端解决方案&#xff0c;允许开发者使用一套代码构建多个平台的应用程序。这些平台包括iOS、Android、H5、微信小程序、支付宝小程序等。uniapp的出现解决了跨平台开发的痛点&#xff0c;大大减少…

ce从初阶到大牛--动态网络部署

1.基于域名www.openlab.com可以访问网站内容为 welcome to openlab!!! systemctl stop firewalld setenforce 0 cd /etc/httpd/conf.d/ vim openlab.conf ** <VirtualHost 192.168.170.100:80>DocumentRoot /www/openlabServerName 192.168.170.100 </VirtualHost>…

排序算法之-选择

算法原理 在未排序的数列中找出最大&#xff08;或最小&#xff09;的元素&#xff0c;然后将其存入到已排序的数列起始位置&#xff0c;紧接着在剩余的未排序数列中继续查找最大&#xff08;或最小&#xff09;的元素&#xff0c;并将其放入到已排序的数列末尾&#xff0c;依…

行情分析——加密货币市场大盘走势(11.6)

大饼昨日下跌过后开始有回调的迹象&#xff0c;现在还是在做指标修复&#xff0c;大饼的策略保持逢低做多。稳健的依然是不碰&#xff0c;目前涨不上去&#xff0c;跌不下来。 以太周五给的策略&#xff0c;入场的已经止盈了&#xff0c;现在已经达到1884&#xff0c;已经全部吃…

Java —— 类和对象(一)

目录 1. 面向对象的初步认知 1.1 什么是面向对象 1.2 面向对象与面向过程 2. 类定义和使用 2.1 认识类 2.2 类的定义格式 3. 类的实例化(如何产生对象) 3.1 什么是实例化 3.2 访问对象的成员 3.3 类和对象的说明 4. this引用 4.1 为什么要有this引用 4.2 什么是this引用 4.3 th…

十一、K8S之持久化存储

持久化存储 一、概念 在K8S中&#xff0c;数据持久化可以让容器在重新调度、重启或者迁移时保留其数据&#xff0c;并且确保数据的可靠性和持久性。 持久化存储通常用于程序的状态数据、数据库文件、日志文件等需要在容器生命周期之外的数据&#xff0c;它可以通过各种存储解…