【C++】拷贝构造函数,析构函数详解!

💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤
📃个人主页 :阿然成长日记 👈点击可跳转
📆 个人专栏: 🔹数据结构与算法🔹C语言进阶
🚩 不能则学,不知则问,耻于问人,决无长进
🍭 🍯 🍎 🍏 🍊 🍋 🍒 🍇 🍉 🍓 🍑 🍈 🍌 🍐 🍍
文章目录
- 一、析构函数
- 1.概念
- 2.特点
- 3.案例
- 二、拷贝构造函数
- 1.拷贝构造函数的引入
- 2.格式
- 2.概念
- 3.特点
- 4.解决引入问题
- 5.总结
一、析构函数
1.概念
析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由
编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。
析构函数是用于在对象被删除之前的清理工作,它在对象生命周期即将结束时会被自动调用。(析构函数可以清理对象并且释放内存)
2.特点
析构函数是特殊的成员函数,其特征如下:
- 析构函数名是在类名前加上字符
~。 - 无参数无返回值类型。
- 一个类只能有一个析构函数。若未显式定义,系统会自动生成
默认的析构函数。注意:析构
函数不能重载 - 对象生命周期结束时,C++编译系统系统自动调用析构函数
- 关于编译器自动生成的析构函数,是否会完成一些事情呢?下面的程序我们会看到,编译器
生成的默认析构函数,对自定类型成员调用它的析构函数
3.案例
class Time
{
public:
~Time()
{
cout << "~Time()" << endl;
}
private:
int _hour;
int _minute;
int _second;
};
class Date
{
private:
// 基本类型(内置类型)
int _year = 1970;
int _month = 1;
int _day = 1;
// 自定义类型
Time _t;
};
int main()
{
Date d;
return 0;
}
上述代码定义了两个类Data和Time。其中Data类中存在一个自定义类型变量Time,主方法中只创建了Data对象。那么在main方法中根本没有直接创建Time类的对象,为什么最后会调用Time类的析构函数?
答:因为main方法中创建了Date对象d,而d中包含4个成员变量,其中_year, _month,_day三个是内置类型成员,销毁时不需要资源清理,最后系统直接将其内存回收即可;而_t是Time类对象,所以在d销毁时,要将其内部包含的Time类的_t对象销毁,需要调用Time类的析构函数。但是main函数中不能直接调用Time类的析构函数,实际要释放的是Date类对象,所以编译器只会调用Date类的析构函 数,而Date没有显式提供,则编译器会给Date类生成一个默认的析构函数,目的是在其内部 调用Time类的析构函数,即当Date对象销毁时,要保证其内部每个自定义对象都可以正确销毁 ,main函数中并没有直接调用Time类析构函数,而是显式调用编译器为Date类生成的默认析构函数
注意:创建哪个类的对象则调用该类的析构函数,销毁那个类的对象则调用该类的析构函数
二、拷贝构造函数
1.拷贝构造函数的引入
如下代码:
创建Stack类和Date类。
class Date
{
public:void print(){}
private:int _year =1;int _month =1;int _day =1;
};
class Stack
{public:Stack(size_t capacity = 10){_array = (DataType*)malloc(capacity * sizeof(DataType));if (nullptr == _array){perror("malloc申请空间失败");return;}_size = 0;_capacity = capacity;}void Push(const DataType& data){// CheckCapacity();_array[_size] = data;_size++;}~Stack(){if (_array){free(_array);_array = nullptr;_capacity = 0;_size = 0;}}private:int* _array;size_t _size;size_t _capacity;
};
使用传值的方式进行调用。
void fun1(Date d)
{//...
}
void fun2(Stack s)
{//...
}
主函数
int main()
{Date d1(1999, 1, 1);fun1(d1);Stack s1;fun2(s1);return 0;
}

可以发现运行报错!!!为什么呢?
在C语言中我们遇到这种情况是没有问题的,但是在C++中,由于引进了析构函数,也就是说每次对象试用结束,系统都会自动调用析构函数进行对象的清除工作,正因如此我们在传值的时候,会再次创建一个对象复制过去,当结束函数调用时,会自动调用析构函数对当前对象进行清除,【如果对象中都是变量的话是没有问题的,因为值传递的改变不影响外部的变量,它只是一份拷贝。但是,如果对象中有指针类型的变量,它们指向的是同一位置,第一次函数调用结束后,析构函数已经对指向的位置进行了清除,第二次外部对象结束时,在调用析构函数,就会造成二次析构】。上面例子中Date类中全是普通变量,不会出现问题,造成二次析构。
为了解决上面的问题我们引入了拷贝构造函数。(通过深拷贝解决问题)
2.格式
类名(const 类名 &参数)
2.概念
只能有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存 在的类类型对象创建新对象时由编译器自动调用。
3.特点
- 拷贝构造函数是构造函数的一个重载形式。
- 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,
因为会引发无穷递归调用。
例如:
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{_year = year;_month = month;_day = day;
}
下面是拷贝构造!!
Date(const Date& ddd) // 正确写法
Date(const Date ddd) // 错误写法:编译报错,会引发无穷递归
{_year = d._year;_month = d._month;_day = d._day;
}
private:int _year;int _month;int _day;
};
主函数
int main()
{Date d1;Date d2(d1);return 0;
}
Date(const Date d)// 错误写法:编译报错,会引发无穷递归; 因为【Date d】参数会继续生成一个拷贝构造,如此往复循环。- *
Date(const Date& ddd)// 正确写法 使用传引用就可以解决这个问题。因为ddd就是对象d1的一个别名,this指针指向d2,ddd传给了this,就相当于把d1给了d2,(传递指针也可以,但是很难用),规定必须使用引用。
4.解决引入问题
学到这里我们就可以很好地解决之前抛出的问题了。使用拷贝构造,将原来对象玩玩整整的拷贝一份出来,尤其是内部指针所指向的空间,拷贝时也会去开辟一块新的空间。这样在函数调用函数结束时,系统自动调用其析构造函数时,就不会造成一个地方多次析构了。各玩各的。
5.总结
内置类型系统会默认生成拷贝构造进行值拷贝,对自定义类型调用它的拷贝构造。
并不是所有的对象都需要拷贝构造:
- 类中如果没有涉及资源申请时(例如 new申请空间),拷贝构造函数是否写都可以;
- 一旦涉及到资源申请时,则拷贝构造函数是一定要写的,否则就是浅拷贝。
- 拷贝构造也是构造,是拷贝构造的一个重载。
相关文章:
【C++】拷贝构造函数,析构函数详解!
💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤 📃个人主页 :阿然成长日记 …...
qml ParticleSystem3D使用介绍
在 Qt Quick 3D 中,ParticleSystem3D 是用来创建和控制3D粒子系统的元素。粒子系统是图形编程中用于模拟液体、烟雾、火、星空等现象的技术,它通过生成大量小粒子来模拟这些效果。ParticleSystem3D 提供了一个框架,允许开发者定义粒子的各种属性,如生命周期、速度、颜色、大…...
集团投融资大数据平台解决方案
一、项目背景 项目为集团型公司大数据平台项目,整个项目周期约为6个月,整体呈现了对外的数据大屏驾驶仓和对内的看板报表,减少了客户内部数据上报和报表制作的重复工作量,为集团数据决策奠定基础。 二、项目目标 战略层ÿ…...
深信服技术认证“SCSA-S”划重点:渗透测试工具使用
为帮助大家更加系统化的学习网络安全知识,尽快通过深信服安全服务认证工程师认证,深信服推出“SCSA-S认证备考秘笈”共十期内容,“考试重点”内容框架,帮助大家快速get重点知识~ 划重点来啦 深信服安全服务认证工程师(…...
CCFCSP试题编号:201803-2试题名称:碰撞的小球
一、题目描述 二、思路 1.首先妾身分析这个题目,想要解题,得得解决2个问题。 1)判断小球到达端点或碰撞然后改变方向; 2)每时刻都要改变位置 两个问题都比较好解决,1)只要简单判断坐标&…...
《安富莱嵌入式周报》第327期:Cortex-A7所有外设单片机玩法LL/HAL库全面上线,分享三款GUI, PX5 RTOS推出网络协议栈,小米Vela开源
周报汇总地址:嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 1、2023 Hackaday大赛胸牌开源 Vectorscope-main.zip (66.83MB) GitHub - Hack-a-Day/Vectorscope: Vectorscope badg…...
面试官:【js多维数组扁平化去重并排序】
文章目录 前言方法一方法二方法三方法四总结后言 前言 hello world欢迎来到前端的新世界 😜当前文章系列专栏:JavaScript 🐱👓博主在前端领域还有很多知识和技术需要掌握,正在不断努力填补技术短板。(如果出现错误&a…...
C#编程题分享(3)
n的阶乘问题 输⼊整数n,输出n的阶乘。 int n Convert.ToInt32(Console.ReadLine()); int jiecheng 1; for (int i 1; i < n 1; i) {jiecheng * i; // 1 * 2 * 3 * .....} Console.WriteLine("{0}的阶乘是:{1}", n, jiecheng); q^n次…...
Redis下载和安装(Windows系统)
通过 GitHub 来下载 Windows 版 Redis 安装包,下载地址:点击前往。 打开上述的下载链接,Redis 支持 32 位和 64 位的 Window 系统,大家根据个人情况自行下载,如图 1 所示: 下载完成后,打开相应的文件夹&a…...
MySQL数据库:开源且强大的关系型数据库管理系统
大家好,我是咕噜-凯撒,数据在当今信息化时代的重要性不可忽视。作为企业和组织的重要资产,数据的管理和存储变得至关重要,MySQL作为一种关系型数据库管理系统,具有非常多的优势,下面简单的探讨一下MySQL数据…...
如何在AD的PCB板做矩形槽孔以及如何倒圆弧角
Altium Designer 22下载安装教程-CSDN博客 如何在AD上创建完整的项目-CSDN博客 开始前,请先安装后AD,并创建好项目。 目录 1. 如何在AD的PCB板做矩形槽孔 2. 如何在AD的PCB板倒圆弧角 1. 如何在AD的PCB板做矩形槽孔 首先,我们进入上面创…...
SpringMVC日志追踪笔记整理
新建logback-spring.xml <?xml version"1.0" encoding"UTF-8"?> <configuration><property name"PATH" value"./log/business"></property><appender name"STDOUT" class"ch.qos.logback…...
UML建模图文详解教程06——顺序图
版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhl本文参考资料:《UML面向对象分析、建模与设计(第2版)》吕云翔,赵天宇 著 顺序图概述 顺序图(sequence diagram,也…...
睡前随笔记录
一个人从出生到长大,就像一部手机从新用到旧。手机里面积累了太多的缓存,积累了太多的照片,各种app的数据,安装了各式各样的程序。 所以大概这就是年纪越大,记性越差的原因吗?就像一个屋子,堆满…...
微服务学习|Feign:快速入门、自定义配置、性能优化、最佳实践
RestTemplate方式调用存在的问题 先来看我们以前利用RestTemplate发起远程调用的代码 存在下面的问题 代码可读性差,编程体验不统一 参数复杂URL难以维护 Feign的介绍 Feign是一个声明式的http客户端,官方地址: https://github.com/OpenFeign/feign …...
使用【画图】软件修改图片像素、比例和大小
打开电脑画图软件,点击开始 windows附件 画图 在画图软件里选择需要调整的照片,点击文件 打开 在弹出窗口中选择照片后点击打开 照片在画图软件中打开后,对照片进行调整。按图中顺序进行 确定后照片会根据设定的值自动调整 保存…...
DevOps 事后分析
众所周知,系统的变化会带来不稳定,进而引发事故。迁移到 DevOps 使世界各地的组织能够以更小的增量和更高的频率进行发布。这降低了特定版本中失败的风险。另一方面,增加发布数量并不一定会减少待命团队需要响应的事件数量。 事件响应团队的…...
fastdfs-client-java-1.30 maven 打包安装
1. 进入源代码目录,打开cmd mvn clean install 或者 mvn package 问题不大的话会在同级目录target目录下生成打包后文件 2. 当前目录下cmd进行maven安装 mvn install:install-file -DgroupIdorg.csource -DartifactIdfastdfs-client-java -Dversion${version} -D…...
【视觉SLAM十四讲学习笔记】第三讲——旋转矩阵
专栏系列文章如下: 【视觉SLAM十四讲学习笔记】第一讲——SLAM介绍 【视觉SLAM十四讲学习笔记】第二讲——初识SLAM 本章将介绍视觉SLAM的基本问题之一:如何描述刚体在三维空间中的运动? 旋转矩阵 点、向量和坐标系 三维空间由3个轴组成&…...
Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo
若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/134533533 红胖子网络科技博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...
C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
解读《网络安全法》最新修订,把握网络安全新趋势
《网络安全法》自2017年施行以来,在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂,网络攻击、数据泄露等事件频发,现行法律已难以完全适应新的风险挑战。 2025年3月28日,国家网信办会同相关部门起草了《网络安全…...
从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践
作者:吴岐诗,杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言:融合数据湖与数仓的创新之路 在数字金融时代,数据已成为金融机构的核心竞争力。杭银消费金…...
为什么要创建 Vue 实例
核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...
jdbc查询mysql数据库时,出现id顺序错误的情况
我在repository中的查询语句如下所示,即传入一个List<intager>的数据,返回这些id的问题列表。但是由于数据库查询时ID列表的顺序与预期不一致,会导致返回的id是从小到大排列的,但我不希望这样。 Query("SELECT NEW com…...
