C++语法|如何写出高效的C++代码(一)|对象使用过程中背后调用了哪些方法(构造和析构过程)?

文章目录

  • 再探拷贝构造函数和重载复制运算符
    • 实例化新对象和赋值操作
    • 强转为类类型
    • 指针和引用时临时对象的构造和析构过程
  • 考考你
    • 问题
    • 答案

再探拷贝构造函数和重载复制运算符

实例化新对象和赋值操作

首先我们写一个类,实现它的拷贝构造并重载赋值运算符。

class Test {
private:int ma;
public:Test(int a = 10): ma(a) {cout << "Test()构造函数" << endl;}~Test() {cout << "~Test析构函数" << endl;}Test(const Test& t) {cout << "Test const Test& t拷贝构造函数" << endl;}Test& operator=(const Test& t) {ma = t.ma;cout << "operator = 重载赋值运算符" << endl;return *this;}
};

然后我们构造类的对象,主要探究什么时候调用重载赋值运算符、什么时候调用拷贝构造

int main () {Test t1;Test t2(t1);Test t3 = t2;Test t4 = Test(20);cout << "-------------" << endl;return 0;
}

结果如下:

为什么没有调用我们的t3和t4没有调用重载赋值运算符呢?

首先t3调用的是拷贝构造函数,说明本质上这是一条构造语句,如果写成

Test t3;
t3 = t2; // 这里调用了重载的赋值运算符

再一个t4是直接调用构造函数,那是因为Test(20)显示生成临时对象,它的生命周期为所在语句,所以它被编译器优化了,实际上调用的是Test t4(20);,如果写成:

//t4.operator=(t2)
t4 = t2; //赋值,没有生成新对象
// t4.operator=(const Test &t)
t4 = Test(20); //这个临时对象会构造一个新对象,然后赋值给t4

此处的Test(20)会就会调用构造函数了,并且t4=会调用重载赋值构造函数,也就是说,只要我们不是在进行初始化对象,而是在赋值某个对象的话,就会调用重载赋值运算符。

强转为类类型

接着上面的代码

t4 = (Test)30; // int->Test

这样能转吗?其实是可以的,编译器会寻找Test类是否有一个合适的构造函数。显然我们这里是有的,因为我们的构造函数默认输入一个整形变量,所以编译器会为我们生成一个临时对象。甚至我们可以写成:这样的话我们是隐式生成临时对象。

t4 = 30;
//t4 = "aaa"; 报错,因为我们没有实现带char*类型的构造函数

指针和引用时临时对象的构造和析构过程

我们想考察一下指针和引用来获取临时对象:

Test *p = &Test(40);
//p指向的是一个已经析构的临时对象,该指针变为野指针
const Test &ref = Test(40);
//Test &ref = Test(30); 报错,必须是常引用

这里的指针甚至不能编译,这是由于较新的编译器代码检查机制更加严格,放以前肯定就编译通过了。并且该指针一定会成为野指针,因为出语句之后临时对象就会析构。并且较新的编译器const Test &ref = Test(40)也会报错,报错语句为:

error: taking the address of a temporary object of type 'Test' [-Waddress-of-temporary]

结论:在较新版本的编译器中,无论是用常引用还是指针,都不能指向一个临时对象

考考你

问题

对于以下类:

class Test {
public:// Test() Test(a) Test(b)Test(int a = 5, int b = 5) : ma(a), mb(b) {cout << "Test()构造函数" << endl;}~Test() {cout << "~Test()析构函数" << endl;}Test(const Test& src) : ma(src.ma), mb(src.mb) {cout << "Test(const Test&)拷贝构造函数" << endl;}Test& operator=(const Test& src) {ma = src.ma;mb = src.mb;cout << "operator=(const Test&)重载赋值运算符" << endl;return *this;}
private:int ma;int mb;
};

我们这样实例化这个类,请问每条语句都调用了类的哪些成员函数呢?

Test t1(10, 10);//1.Test(int, int)
int main() {Test t2(20, 20);//3.Test(int, int)Test t3 = t2; //4.Test(const Test&)/*静态变量和全局变量程序运行的时候内存就已经存在了,因为数据段内存是事先就分配好的但是静态局部变量只在第一次运行到它才会初始化,所以并不会构造先t4*///static Test t4(30,30);static Test t4 = Test(30, 30);//5.Test(int, int)t2 = Test(40, 40); //6.Test(int, int) operator= ~Test()//(50, 50) = 50 逗号表达式t2 = (Test)(50, 50);//7.(Test)50; Test(int, int) operator= ~Test()t2 = 60;	// Test(int) 8.Test(int, int) operator= ~Test()Test *p1 = new Test(70, 70); //9. Test(int, int)Test *p2 = new Test[2]; // 10. Test(int, int) Test(int, int)//较新的编译器无法通过编译Test *p3 = &Test(80, 80);  //11.Test(int, int) ~Test()const Test &p4 = Test(90, 90); //12.Test(int, int)delete p1; //13.~Test() 然后free内存delete[]p2; //14.~Test() ~Test() 然后free内存
}
Test t5(100, 100); //2. Test(int, int)

运行以后,这个类的构造、析构、拷贝构造的调用过程已经写在注释中了,并且最后的析构顺序为p1->p2->p4->t3->t2->t4->t5->t1 一共应该是9连析构

答案

你答对了吗?(这里的输出结果是注释Test *p3 = &Test(80, 80);后的结果)

在这里插入图片描述

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

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

相关文章

数值计算方法——大题题型总结

目录 一、绝对误差限、相对误差限 1.1 例题 1.2 解题套路 1.3 题解 二、敛散性、收敛速度 2.1 例题 2.2 解题套路 2.3 题解 三、牛顿迭代法 3.1 例题 3.2 解题套路 3.3 题解 四、割线法 4.1 例题 4.2 解题套路 ​4.3 题解 五、列主元素消去法 5.1 例题 5.…

python爬虫实战

import requests import json yesinput(输入页数&#xff1a;) yesint(yes)headers {"accept": "application/json, text/plain, */*","accept-language": "zh-CN,zh;q0.9","content-type": "application/json",…

JAVA基础之jsp标准标签

jsp动作标签实现实例化一个实体类 <jsp:useBean id"标识符" class"java类名" scope"作用范围"> 传统的java方式实例化一个实体类 Users user new Users(); <%%> id: 对象名 * class:类 创建对象时,完全限定名(包名…

Linux基础之yum和vim

目录 一、软件包管理器yum 1.1 软件包的概念 1.2 软件包的查看 1.3 软件包的安装和删除 二、Linux编辑器之vim 2.1 vim的基本概念 2.2 正常模式&#xff08;命令模式&#xff09; 2.3 底行模式 2.4 输入模式 2.5 替换模式 2.6 视图模式 2.7 总结 一、软件包管理器yu…

嵌入式Linux学习第四天启动方式学习

嵌入式Linux学习第四天 今天学习I.MX6U 启动方式详解。I.MX6U有多种启动方式&#xff0c;可以从 SD/EMMC、NAND Flash、QSPI Flash等启动。 启动方式选择 BOOT 的处理过程是发生在 I.MX6U 芯片上电以后&#xff0c;芯片会根据 BOOT_MODE[1:0]的设置来选择 BOOT 方式。BOOT_M…

Spring - 9 ( 10000 字 Spring 入门级教程 )

一&#xff1a; MyBatis XML 配置文件 Mybatis 的开发有两种方式&#xff1a; 注解XML 我们已经学习了注解的方式, 接下来我们学习 XML 的方式 MyBatis XML 的方式需要以下两步: 配置数据库连接字符串和 MyBatis写持久层代码 1.1 配置连接字符串和 MyBatis 此步骤需要进…

STC8增强型单片机开发 【第一个程序 - 点亮第一盏灯】

目录 一、创建项目 1. 创建一个新的项目 ​编辑 2. 配置开发板信息 ​编辑 3. 取消汇编配置 4. 项目结构 二、编码实现 1. 项目准备 2. 代码实现 点灯&#xff1a; 熄灯&#xff1a; 3. 编译烧录运行 配置编译输出 保存和编译代码 ​编辑 烧录 一、创建项目 1. …

OceanBase 如何实现多层面的资源隔离

OceanBase的资源隔离涵盖了多个方面&#xff0c;如物理机器间的隔离、不同租户之间的隔离、同一租户内的隔离&#xff0c;以及针对大型查询请求的隔离等。在实际应用OceanBase的过程中&#xff0c;我们经常会遇到这些操作场景或产生相关需求。这篇文章针对这些内容进行了简要的…

阿里云SLB监听虚拟服务器组时,既有部署在k8s容器里的应用,又有部署在ecs机器上的应用,k8s应用无法连接部署在ecs机器上的应用

一、背景 阿里云SLB可以添加多个监听端口&#xff0c;包括http和tcp&#xff0c;但是当被添加的后端应用&#xff0c;既有部署在k8s里&#xff0c;也有部署在ecs机器里。同一个slb下&#xff0c;这种混合方式的监听&#xff0c;会导致部署在k8s应用中的应用无法连接后者&#…

Spring扩展点(一)Bean生命周期扩展点

Bean生命周期扩展点 影响多个Bean的实例化InstantiationAwareBeanPostProcessorBeanPostProcessor 影响单个Bean的实例化纯粹的生命周期回调函数InitializingBean&#xff08;BeanPostProcessor 的before和after之间调用&#xff09;DisposableBean Aware接口在生命周期实例化过…

内存卡突然罢工?数据恢复有高招!

内存卡作为我们日常生活中常见的存储设备&#xff0c;广泛应用于手机、相机等设备中。然而&#xff0c;有时我们会遇到内存卡损坏打不开的情况&#xff0c;这时该如何应对呢&#xff1f;本文将为您详细解析内存卡损坏的原因&#xff0c;并提供有效的数据恢复方案&#xff0c;帮…

FPGA第二篇,FPGA与CPU GPU APU DSP NPU TPU 之间的关系与区别

简介&#xff1a;首先&#xff0c;FPGA与CPU GPU APU NPU TPU DSP这些不同类型的处理器&#xff0c;可以被统称为"处理器"或者"加速器"。它们在计算机硬件系统中承担着核心的计算和处理任务&#xff0c;可以说是系统的"大脑"和"加速引擎&qu…

如何进行Go语言的性能测试和调优?

文章目录 开篇一、性能测试1. 使用标准库中的testing包2. 使用第三方工具 二、性能调优1. 优化算法和数据结构2. 减少不必要的内存分配和垃圾回收3. 并发和并行 结尾 开篇 Go语言以其出色的性能和简洁的语法受到了广大开发者的喜爱。然而&#xff0c;在实际开发中&#xff0c;…

Linux进程——Linux进程间切换与命令行参数

前言&#xff1a;在上一篇了解完进程状态后&#xff0c;我们简单了解了进程优先级&#xff0c;然后遗留了一点内容&#xff0c;本篇我们就来研究进程间的切换&#xff0c;来理解上篇提到的并发。如果对进程优先级还有没理解的地方可以先阅读&#xff1a; Linux进程优先级 本篇…

Python程序设计 函数(三)

练习十一 函数 第1关&#xff1a; 一元二次方程的根 定义一个函数qg&#xff0c;输入一元二次方程的系数a,b,c 当判别式大于0&#xff0c;返回1和两个根 当判别式等于0&#xff0c;返回0和两个根 当判别式小于0&#xff0c;访问-1和两个根 在主程序中&#xff0c;根据函数返回…

Vue3:menu导航栏出现多个同一跳转路径的菜单处理

文章目录 需求整理实现思路实现过程 需求整理&#xff0c;实现思路 最近公司想将之前老的项目整理出来&#xff0c;因为这个老项目内容太杂什么页面都往里面塞&#xff0c;导致菜单特别多&#xff0c;公司就像将这个老的项目迁出来&#xff0c;这个旧的项目本来是后端PHP写的。…

【3dmax笔记】035: 车削修改器

一、车削修改器介绍 车削&#xff1a;图形通过绕轴旋转来创建三维效果。 开放的样条线&#xff0c;车削之后是面片。闭合的样条线&#xff0c;车削之后&#xff0c;是实体。 一、车削修改器实例 绘制高脚杯&#xff0c;首先在前视图绘制如下二维图形。 添加一个车削的修改器…

LeetCode509:斐波那契数(使用动态规划)

题目描述 斐波那契数 &#xff08;通常用 F(n) 表示&#xff09;形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始&#xff0c;后面的每一项数字都是前面两项数字的和。也就是&#xff1a; F(0) 0&#xff0c;F(1) 1 F(n) F(n - 1) F(n - 2)&#xff0c;其中 n > 1…

【Linux】gcc/g++的使用

&#x1f389;博主首页&#xff1a; 有趣的中国人 &#x1f389;专栏首页&#xff1a; Linux &#x1f389;其它专栏&#xff1a; C初阶 | C进阶 | 初阶数据结构 小伙伴们大家好&#xff0c;本片文章将会讲解Linux中gcc/g使用的相关内容。 如果看到最后您觉得这篇文章写得不错…

深入了解 NumPy:深度学习中的数学运算利器

文章目录 1. 导入NumPy2. 创建NumPy数组3. 数组的算术运算4. N维数组4.1 创建和操作多维数组4.2 高维数组 5. NumPy的广播功能5.1 基本广播示例5.2 更复杂的广播示例 6. 访问数组元素6.1 基于索引的访问6.2 遍历数组6.3 基于条件的访问6.4 高级索引6.5 性能考虑 在深度学习和数…