【C++ | 拷贝构造函数】一文了解C++的 拷贝(复制)构造函数

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
⏰发布时间⏰:2024-06-07 21:05:34

本文未经允许,不得转发!!!

目录

  • 🎄一、为什么需要 拷贝构造函数
  • 🎄二、什么是 拷贝构造函数
  • 🎄三、使用 拷贝构造函数
  • 🎄四、默认的 拷贝构造函数
  • 🎄五、总结



在这里插入图片描述

🎄一、为什么需要 拷贝构造函数

如果程序中出现需要 拷贝构造函数 的代码,而又没有提供拷贝构造函数时,系统会提供一个默认的拷贝构造函数,该函数只会完成浅拷贝而不会进行深拷贝,这就是为什么需要 拷贝构造函数 的原因。

关于浅拷贝、深拷贝的知识,可以看这篇文章:C++入门知识-拷贝构造函数-浅拷贝、深拷贝

下面用例子说明浅拷贝可能产生的问题:

// g++ 11_Copy_Constructor_Date.cpp
#include <iostream>
#include <stdio.h>using namespace std;class CDate
{
public:CDate(int year, int mon, int day);	// 构造函数声明~CDate();							// 析构函数声明void show(){//cout << "Date: " << m_year << "." << m_mon << "." << m_day << endl;cout << "Date: " << str << endl;}private:int m_year;int m_mon;int m_day;char *str;
};// 构造函数定义
CDate::CDate(int year, int mon, int day)
{m_year = year;m_mon = mon;m_day = day;str = new char[64];sprintf(str, "%4d.%02d.%02d", year,mon,day);cout << "Calling Constructor" << ", this=" << this <<endl;
}// 析构函数定义
CDate::~CDate()
{cout << "Calling Destructor" << ", this=" << this <<endl;delete [] str;
}int main()
{CDate date_1(2024,06,05);CDate date_2 = date_1;	// 调用拷贝构造函数date_1.show();date_2.show();return 0;
}

上面代码由于没有进行深拷贝,导致 double free 了的错误,因为浅拷贝只复制了str的值,在两个对象销毁时都delete了。
在这里插入图片描述


在这里插入图片描述

🎄二、什么是 拷贝构造函数

拷贝构造函数,有些书也把其成为复制构造函数,其作用是将一个对象复制到新创建的对象中。

类的拷贝构造函数原型通常是这样的:类名(const 类名 &);。以CDate类为例,其拷贝构造函数如下:

CDate(const CDate &);

拷贝构造函数的几个特点:
1、函数名和类名相同,因为它也是构造函数的一种;
2、第一个参数必须是一个自身类类型的引用,且其他参数都有默认值。
3、第一个参数必须是自身类类型的引用的原因:如果不上引用则需要拷贝它的实参,为了要拷贝实参,又需要调用拷贝构造函数,如此无限循环;

清楚了这些之后,我们修改一下上个小节的代码,添加一个拷贝构造函数:

// g++ 11_Copy_Constructor_Date.cpp
#include <iostream>
#include <stdio.h>using namespace std;class CDate
{
public:CDate(int year, int mon, int day);	// 构造函数声明CDate(const CDate& date);			// 拷贝构造函数声明~CDate();							// 析构函数声明void show(){//cout << "Date: " << m_year << "." << m_mon << "." << m_day << endl;cout << "Date: " << str << endl;}private:int m_year;int m_mon;int m_day;char *str;
};// 构造函数定义
CDate::CDate(int year, int mon, int day)
{m_year = year;m_mon = mon;m_day = day;str = new char[64];sprintf(str, "%4d.%02d.%02d", year,mon,day);cout << "Calling Constructor" << ", this=" << this <<endl;
}// 拷贝构造函数定义
CDate::CDate(const CDate& date)
{m_year = date.m_year;m_mon = date.m_mon;m_day = date.m_day;str = new char[64];sprintf(str, "%4d.%02d.%02d", m_year,m_mon,m_day);cout << "Calling Copy Constructor" << ", this=" << this <<endl;
}// 析构函数定义
CDate::~CDate()
{cout << "Calling Destructor" << ", this=" << this <<endl;delete [] str;
}int main()
{CDate date_1(2024,06,05);CDate date_2 = date_1;	// 调用date_2的拷贝构造函数date_1.show();date_2.show();return 0;
}

运行结果如下,添加拷贝构造函数后,运行不会报错,因为拷贝构造函数中重新new了内存:
在这里插入图片描述


在这里插入图片描述

🎄三、使用 拷贝构造函数

为了使用 拷贝构造函数,我们必须清楚 拷贝构造函数 在什么情况下会被调用,然后再根据自己设计的类是否需要深拷贝来决定怎样定义该类的 拷贝构造函数

会调用拷贝构造函数的几种情况:

  1. 使用同类型的对象去初始化另一个对象时。
    如下代码,使用了 date_1 初始化 date_2:
    CDate date_1(2024,06,05);
    CDate date_2 = date_1;	// 调用date_2的拷贝构造函数
    
  2. 将一个对象作为实参传递给一个非引用类型的形参。
    void printDate(CDate date)
    {date.show();
    }
    ...
    printDate(date_2);	// 实参传值到形参,调用拷贝构造函数
    
  3. 从一个返冋类型为非引用类型的函数返回一个对象。
    CDate g_date(2024,06,06);;
    CDate getDate()
    {return g_date;	// 3、返回对象时,调用拷贝构造函数
    }
    

下面例子演示了调用拷贝构造函数的这三种场景:

// g++ 11_Copy_Constructor_Date.cpp
#include <iostream>
#include <stdio.h>using namespace std;class CDate
{
public:CDate(int year, int mon, int day);	// 构造函数声明CDate(const CDate& date);			// 拷贝构造函数声明~CDate();							// 析构函数声明void show(){//cout << "Date: " << m_year << "." << m_mon << "." << m_day << endl;cout << "Date: " << str << endl;}private:int m_year;int m_mon;int m_day;char *str;
};// 构造函数定义
CDate::CDate(int year, int mon, int day)
{m_year = year;m_mon = mon;m_day = day;str = new char[64];sprintf(str, "%4d.%02d.%02d", year,mon,day);cout << "Calling Constructor" << ", this=" << this <<endl;
}// 拷贝构造函数定义
CDate::CDate(const CDate& date)
{m_year = date.m_year;m_mon = date.m_mon;m_day = date.m_day;str = new char[64];sprintf(str, "%4d.%02d.%02d", m_year,m_mon,m_day);cout << "Calling Copy Constructor" << ", this=" << this <<endl;
}// 析构函数定义
CDate::~CDate()
{cout << "Calling Destructor" << ", this=" << this <<endl;delete [] str;
}void printDate(CDate date)
{date.show();
}CDate g_date(2024,06,06);;
CDate getDate()
{return g_date;	// 3、返回对象时,调用拷贝构造函数
}int main()
{CDate date_1(2024,06,05);CDate date_2 = date_1;	// 1、调用date_2的拷贝构造函数date_1.show();date_2.show();cout << endl;printDate(date_2);	// 2、实参传值到形参,调用拷贝构造函数cout << endl;getDate();cout << endl;return 0;
}

运行结果:
在这里插入图片描述


在这里插入图片描述

🎄四、默认的 拷贝构造函数

如果没有为一个类定义拷贝构造函数,则编译器会合成一个“默认拷贝构造函数”。

默认的拷贝构造函数会逐个复制非静态成员( 成员复制也称为浅复制)的值到正在创建的对象中。根据成员类型有下面几种情况:
1、如果成员是内置类型,则直接复制;
2、如果成员本身就是类对象,则将使用这个类的拷贝构造函数来复制类对象;
3、如果成员是数组,默认的拷贝构造函数会逐元素地拷贝一个数组类型的成员。


在这里插入图片描述

🎄五、总结

👉本文介绍C++的拷贝构造函数,为什么需要拷贝构造函数,什么是拷贝构造函数,怎么使用拷贝构造函数,默认拷贝构造函数。

在这里插入图片描述
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁

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

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

相关文章

链表题目练习----重排链表

这道题会联系到前面写的一篇文章----快慢指针相关经典问题。 重排链表 指针法 这道题乍一看&#xff0c;好像有点难处理&#xff0c;但如果仔细观察就会发现&#xff0c;这道题是查找中间节点反转链表链表的合并问题&#xff0c;具体细节有些不同&#xff0c;这个在反装中间链…

如何有效提问?

有效提问&#xff1a;正确地向别人提问是一种艺术&#xff0c;可以帮助你获得清晰、有用的答案。 明确表达问题&#xff1a;确保你的问题清晰明了&#xff0c;避免含糊不清或模棱两可的语言。这可以帮助对方更好地理解你的问题&#xff0c;并给出准确的答复。 尊重对方&#x…

毕业论文word常见问题

0、前言&#xff1a; 这里的问题都是以office办公软件当中的word为例&#xff0c;和WPS没有关系。 1、页眉横线删不掉&#xff1a; 解决方案&#xff1a;进入页眉编辑状态&#xff0c;在开始选项栏中选择页眉字体样式&#xff0c;清除格式。 修改方式如下&#xff1a; 2、…

社区服务支持

社区服务支持 原创 小王搬运工 时序课堂 2024-06-07 19:29 四川 &#x1f31f; 邀请函 | 加入我们的时序数据挖掘社区 &#x1f680; 尊敬的数据爱好者们&#xff0c; 我们诚挚地邀请您加入我们的专业社区——时序数据挖掘社区&#xff0c;一个专注于时序数据分析、挖掘与应…

QT 信号和槽 多对一关联示例,多个信号,一个槽函数响应,多个信号源如何绑定一个槽函数

三个顾客 Anderson、Bruce、Castiel 都要订饭&#xff0c;分别对应三个按钮&#xff0c;点击一个按钮&#xff0c;就会弹出给该顾客送饭的消息。注意这个例子只使用一个槽函数&#xff0c;而三个顾客名称是不一样的&#xff0c;弹窗时显示的消息不一样&#xff0c;这需要一些 技…

什么情况下要配置DNS服务

什么是DNS 一、DNS就是域名解析 我们上网的方式通常都由ip地址组成&#xff0c;但是为了有个规范&#xff0c;而且我们也不可能去记住那么多一串Ip数字&#xff0c;首先域名就会比ip好记很多&#xff0c;其次固定性&#xff0c;一旦服务器换了&#xff0c;只要重新绑定域名对…

【Flutter】 TextField限制长度时, 第三方手写输入法、ios原始拼音输入法输入被吞问题

问题描述 TextField限制长度时&#xff0c; 当你的输入字符长度已经到了最大值-1时&#xff0c;使用第三方手写输入法或者ios原生拼音输入法输入liang&#xff08;什么拼音都行&#xff0c;这里只是举例&#xff09;&#xff0c;输到i那么li都会消失。 原因分析 这是因为第三…

C++青少年简明教程:C++函数

C青少年简明教程&#xff1a;C函数 C函数是一段可重复使用的代码&#xff0c;用于执行特定的任务&#xff0c;可以提高代码的可读性和可维护性。函数可以接受参数&#xff08;输入&#xff09;并返回一个值&#xff08;输出&#xff09;&#xff0c;也可以没有参数和返回值。 …

Nvidia/算能 +FPGA+AI大算力边缘计算盒子:中国舰船研究院

中国舰船研究院又称中国船舶重工集团公司第七研究院&#xff0c;隶属于中国船舶重工集团公司&#xff0c;是专门从事舰船研究、设计、开发的科学技术研究机构&#xff0c;是中国船舶重工集团公司的军品技术研究中心、科技开发中心&#xff1b;主要从事舰船武器装备发展战略研究…

【spring】第一篇 IOC和DI入门案例

Spring到底是如何来实现IOC和DI的&#xff0c;那接下来就通过一些简单的入门案例&#xff0c;来演示下具体实现过程。 目录 前期准备 一、IOC入门案例 思路分析 代码实现 二、DI入门案例 思路分析 代码实现 总结 前期准备 使用IDEA创建Maven项目&#xff0c;首先需要配…

实验11 OSPF协议配置

实验11 OSPF协议配置 一、OSPF单区域配置&#xff08;一&#xff09;原理描述&#xff08;二&#xff09;实验目的&#xff08;三&#xff09;实验内容&#xff08;四&#xff09;实验配置&#xff08;五&#xff09;实验步骤 二、OSPF多区域配置&#xff08;一&#xff09;原理…

环 境 变 量

如果希望某一个文件在 CMD 窗口的任意路径下都可以打开&#xff0c;则需要将该文件的路径存放在环境变量中。 在 CMD 中运行该文件时&#xff0c;优先查看当前路径下的文件&#xff0c;如果没有找到&#xff0c;则进入环境变量中记录的路径下寻找该文件&#xff0c;如果能找到…

泛微开发修炼之旅--10基于Ecology实现附件上传,并将上传后的文件id存入表单附件控件中的示例及源码

文章链接&#xff1a;泛微开发修炼之旅--10基于Ecology实现附件上传&#xff0c;并将上传后的文件id存入表单附件控件中的示例及源码

2024年人力资源与社会治理国际会议(ICHRSG 2024)

2024年人力资源与社会治理国际会议 2024 International Conference on Human Resources and Social Governance 会议简介 2024年人力资源与社会治理国际会议是一个聚焦全球人力资源发展与社会治理创新的高端交流平台。本次会议汇集了全球顶尖的专家学者、企业高管和政策制定者&…

二轴机器人大米装箱机:技术创新引领智能包装新潮流

在科技日新月异的今天&#xff0c;自动化和智能化已成为各行各业追求高效、精准生产的关键。作为粮食加工行业的重要一环&#xff0c;大米装箱机的技术创新与应用价值日益凸显。其中&#xff0c;二轴机器人大米装箱机以其高效、稳定、智能的特点&#xff0c;成为市场的新宠。星…

深入理解feign远程调用的各种超时参数

1. 引言 在spring cloud微服中&#xff0c;feign远程调用可能是大家每天都接触到东西&#xff0c;但很多同学却没咋搞清楚这里边的各种超时问题&#xff0c;生产环境可能会蹦出各种奇怪的问题。 首先说下结论&#xff1a; 1)只使用feign组件&#xff0c;不使用ribbion组件&…

玄机平台应急响应—apache日志分析

1、前言 apache的日志一共有两个&#xff0c;一个是access.log&#xff0c;这个日志记录了所有对Web服务器的访问&#xff0c;被入侵时重点排查这个。另一个是error.log&#xff0c;错误日志记录了服务器运行期间遇到的各种错误&#xff0c;以及一些普通的诊断信息&#xff0c…

纵向导航栏使用navbar-nav-scroll溢出截断问题

项目场景&#xff1a; 组件&#xff1a;Bootstrap-4.6.2、JQuery 3.7.1 测试浏览器&#xff1a;Firefox126.0.1、Microsoft Edge125.0.2535.67 IDE&#xff1a;eclipes2024-03.R 在编写CRM的工作台主页面时&#xff0c;由于该页面使用的是较旧的技术&#xff0c;所以打算使用…

安全U盘和普通U盘有什么区别?

安全U盘&#xff08;也称为加密U盘或安全闪存驱动器&#xff09;与普通U盘肯定是有一些区别的&#xff0c;从字面意思上来看&#xff0c;就能看出&#xff0c;安全U盘是能够保护文件数据安全性的&#xff0c;普通U盘没这一些功能的&#xff0c;可随意拷贝文件&#xff0c;不防盗…

Django里的ModelForm组件

ModelForm组件 自动生成HTML标签 自动读取关联数据表单验证 保留之前提交的数据 错误提示数据库进行&#xff1a;新建&#xff0c;修改 步骤如下&#xff1a; 创建类 # 在 views.py 文件里# 创建一个类 class AssetModelForm(forms.ModelForm):class Meta:model models.…