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

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

在这里插入图片描述

💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤
📃个人主页 :阿然成长日记 👈点击可跳转
📆 个人专栏: 🔹数据结构与算法🔹C语言进阶
🚩 不能则学,不知则问,耻于问人,决无长进
🍭 🍯 🍎 🍏 🍊 🍋 🍒 🍇 🍉 🍓 🍑 🍈 🍌 🍐 🍍

文章目录

  • 一、析构函数
    • 1.概念
    • 2.特点
    • 3.案例
  • 二、拷贝构造函数
    • 1.拷贝构造函数的引入
    • 2.格式
    • 2.概念
    • 3.特点
    • 4.解决引入问题
    • 5.总结

一、析构函数

1.概念

析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由
编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。
析构函数是用于在对象被删除之前的清理工作,它在对象生命周期即将结束时会被自动调用。(析构函数可以清理对象并且释放内存)

2.特点

析构函数是特殊的成员函数,其特征如下:

  1. 析构函数名是在类名前加上字符 ~
  2. 无参数无返回值类型。
  3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构
    函数不能重载
  4. 对象生命周期结束时,C++编译系统系统自动调用析构函数
  5. 关于编译器自动生成的析构函数,是否会完成一些事情呢?下面的程序我们会看到,编译器
    生成的默认析构函数,对自定类型成员调用它的析构函数

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三个是内置类型成员,销毁时不需要资源清理,最后系统直接将其内存回收即可;而_tTime类对象,所以在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.特点

  1. 拷贝构造函数是构造函数的一个重载形式。
  2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,
    因为会引发无穷递归调用。

例如:

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++】拷贝构造函数,析构函数详解!

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …...

qml ParticleSystem3D使用介绍

在 Qt Quick 3D 中,ParticleSystem3D 是用来创建和控制3D粒子系统的元素。粒子系统是图形编程中用于模拟液体、烟雾、火、星空等现象的技术,它通过生成大量小粒子来模拟这些效果。ParticleSystem3D 提供了一个框架,允许开发者定义粒子的各种属性,如生命周期、速度、颜色、大…...

集团投融资大数据平台解决方案

一、项目背景 项目为集团型公司大数据平台项目&#xff0c;整个项目周期约为6个月&#xff0c;整体呈现了对外的数据大屏驾驶仓和对内的看板报表&#xff0c;减少了客户内部数据上报和报表制作的重复工作量&#xff0c;为集团数据决策奠定基础。 二、项目目标 战略层&#xff…...

深信服技术认证“SCSA-S”划重点:渗透测试工具使用

为帮助大家更加系统化的学习网络安全知识&#xff0c;尽快通过深信服安全服务认证工程师认证&#xff0c;深信服推出“SCSA-S认证备考秘笈”共十期内容&#xff0c;“考试重点”内容框架&#xff0c;帮助大家快速get重点知识~ 划重点来啦 深信服安全服务认证工程师&#xff08;…...

CCFCSP试题编号:201803-2试题名称:碰撞的小球

一、题目描述 二、思路 1.首先妾身分析这个题目&#xff0c;想要解题&#xff0c;得得解决2个问题。 1&#xff09;判断小球到达端点或碰撞然后改变方向&#xff1b; 2&#xff09;每时刻都要改变位置 两个问题都比较好解决&#xff0c;1&#xff09;只要简单判断坐标&…...

《安富莱嵌入式周报》第327期:Cortex-A7所有外设单片机玩法LL/HAL库全面上线,分享三款GUI, PX5 RTOS推出网络协议栈,小米Vela开源

周报汇总地址&#xff1a;嵌入式周报 - 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欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;JavaScript &#x1f431;‍&#x1f453;博主在前端领域还有很多知识和技术需要掌握&#xff0c;正在不断努力填补技术短板。(如果出现错误&a…...

C#编程题分享(3)

n的阶乘问题 输⼊整数n&#xff0c;输出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}的阶乘是&#xff1a;{1}", n, jiecheng); q^n次…...

Redis下载和安装(Windows系统)

通过 GitHub 来下载 Windows 版 Redis 安装包,下载地址&#xff1a;点击前往。 打开上述的下载链接&#xff0c;Redis 支持 32 位和 64 位的 Window 系统&#xff0c;大家根据个人情况自行下载&#xff0c;如图 1 所示&#xff1a; 下载完成后&#xff0c;打开相应的文件夹&a…...

MySQL数据库:开源且强大的关系型数据库管理系统

大家好&#xff0c;我是咕噜-凯撒&#xff0c;数据在当今信息化时代的重要性不可忽视。作为企业和组织的重要资产&#xff0c;数据的管理和存储变得至关重要&#xff0c;MySQL作为一种关系型数据库管理系统&#xff0c;具有非常多的优势&#xff0c;下面简单的探讨一下MySQL数据…...

如何在AD的PCB板做矩形槽孔以及如何倒圆弧角

Altium Designer 22下载安装教程-CSDN博客 如何在AD上创建完整的项目-CSDN博客 开始前&#xff0c;请先安装后AD&#xff0c;并创建好项目。 目录 1. 如何在AD的PCB板做矩形槽孔 2. 如何在AD的PCB板倒圆弧角 1. 如何在AD的PCB板做矩形槽孔 首先&#xff0c;我们进入上面创…...

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——顺序图

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl本文参考资料&#xff1a;《UML面向对象分析、建模与设计&#xff08;第2版&#xff09;》吕云翔&#xff0c;赵天宇 著 顺序图概述 顺序图(sequence diagram&#xff0c;也…...

睡前随笔记录

一个人从出生到长大&#xff0c;就像一部手机从新用到旧。手机里面积累了太多的缓存&#xff0c;积累了太多的照片&#xff0c;各种app的数据&#xff0c;安装了各式各样的程序。 所以大概这就是年纪越大&#xff0c;记性越差的原因吗&#xff1f;就像一个屋子&#xff0c;堆满…...

微服务学习|Feign:快速入门、自定义配置、性能优化、最佳实践

RestTemplate方式调用存在的问题 先来看我们以前利用RestTemplate发起远程调用的代码 存在下面的问题 代码可读性差&#xff0c;编程体验不统一 参数复杂URL难以维护 Feign的介绍 Feign是一个声明式的http客户端&#xff0c;官方地址: https://github.com/OpenFeign/feign …...

使用【画图】软件修改图片像素、比例和大小

打开电脑画图软件&#xff0c;点击开始 windows附件 画图 在画图软件里选择需要调整的照片&#xff0c;点击文件 打开 在弹出窗口中选择照片后点击打开 照片在画图软件中打开后&#xff0c;对照片进行调整。按图中顺序进行 确定后照片会根据设定的值自动调整 保存…...

DevOps 事后分析

众所周知&#xff0c;系统的变化会带来不稳定&#xff0c;进而引发事故。迁移到 DevOps 使世界各地的组织能够以更小的增量和更高的频率进行发布。这降低了特定版本中失败的风险。另一方面&#xff0c;增加发布数量并不一定会减少待命团队需要响应的事件数量。 事件响应团队的…...

fastdfs-client-java-1.30 maven 打包安装

1. 进入源代码目录&#xff0c;打开cmd mvn clean install 或者 mvn package 问题不大的话会在同级目录target目录下生成打包后文件 2. 当前目录下cmd进行maven安装 mvn install:install-file -DgroupIdorg.csource -DartifactIdfastdfs-client-java -Dversion${version} -D…...

【视觉SLAM十四讲学习笔记】第三讲——旋转矩阵

专栏系列文章如下&#xff1a; 【视觉SLAM十四讲学习笔记】第一讲——SLAM介绍 【视觉SLAM十四讲学习笔记】第二讲——初识SLAM 本章将介绍视觉SLAM的基本问题之一&#xff1a;如何描述刚体在三维空间中的运动&#xff1f; 旋转矩阵 点、向量和坐标系 三维空间由3个轴组成&…...

Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/134533533 红胖子网络科技博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬…...

HTML 语义化

目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案&#xff1a; 语义化标签&#xff1a; <header>&#xff1a;页头<nav>&#xff1a;导航<main>&#xff1a;主要内容<article>&#x…...

docker详细操作--未完待续

docker介绍 docker官网: Docker&#xff1a;加速容器应用程序开发 harbor官网&#xff1a;Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台&#xff0c;用于将应用程序及其依赖项&#xff08;如库、运行时环…...

基于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 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...

解读《网络安全法》最新修订,把握网络安全新趋势

《网络安全法》自2017年施行以来&#xff0c;在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂&#xff0c;网络攻击、数据泄露等事件频发&#xff0c;现行法律已难以完全适应新的风险挑战。 2025年3月28日&#xff0c;国家网信办会同相关部门起草了《网络安全…...

从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践

作者&#xff1a;吴岐诗&#xff0c;杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言&#xff1a;融合数据湖与数仓的创新之路 在数字金融时代&#xff0c;数据已成为金融机构的核心竞争力。杭银消费金…...

为什么要创建 Vue 实例

核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...

jdbc查询mysql数据库时,出现id顺序错误的情况

我在repository中的查询语句如下所示&#xff0c;即传入一个List<intager>的数据&#xff0c;返回这些id的问题列表。但是由于数据库查询时ID列表的顺序与预期不一致&#xff0c;会导致返回的id是从小到大排列的&#xff0c;但我不希望这样。 Query("SELECT NEW com…...