类的默认成员函数【拷贝(复制)构造函数】

2023-11-07

拷贝(复制)构造函数

用一个已经存在的对象初始化另一个新对象时,编译器会自动调用拷贝构造函数。


1、拷贝构造函数是构造函数的一种重载形式

2、拷贝构造函数的参数:单个形参,传递const类类型的引用

1)如果传值引用,会引发无穷调用
在这里插入图片描述
2)如果不加const,可能会因为我们不小心写错代码,改变已经存在的对象

例1:拷贝构造函数参数不加const

class Date
{
public:
	Date(int year = 2000, int month = 4, int day = 21)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	// 拷贝构造函数
	Date(Date& d) // 不加const
	{
		_year = d._year;
		_month = d._month;
		_day = d._day++; // 假如这我们不小心写错了
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(2021, 4, 19);
	Date d2(d1);

	system("pause");
	return 0;
}

创建d1调用构造函数之后,初始化好的d1对象中的成员变量的值如下图:
在这里插入图片描述当我们调用拷贝构造函数初始化完d2后,d1的值发生了改变,我们只是想用d1的值初始化d2,却把d1改了,这岂不是很离谱在这里插入图片描述
当我们加上const,它就不允许我们修改了,这就防止了我们手滑写错
在这里插入图片描述

3、编译器自动调用拷贝构造函数的三种情况

1) 用一个对象初始化同类的另一个对象

2)当函数的参数为类的对象时。在调用函数时需要将实参对象完整的传递给形参,形参实例化时会对实参进行拷贝,按实参复制一个形参,系统通过调用拷贝构造函数来实现的,这样能保证形参具有和实参完全相同的值

3)函数的返回值是类的对象。在函数调用完毕将返回值带回函数调用处时。此时需要将函数中的对象复制一个临时对象并传给该函数的调用处。

未显式定义拷贝构造函数,编译器自动生成的默认拷贝构造函数的拷贝方式是浅拷贝

4、必须显式定义拷贝构造函数的场景

1)当类中不涉及资源管理时,我们自己显式定义的拷贝构造函数和编译器自动生成的,最终效果是一样的

例2:Date类中不涉及资源管理

① 显式定义拷贝构造函数

class Date
{
public:
	Date(int year = 2000, int month = 4, int day = 21)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	// 拷贝构造函数
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(2021, 4, 19); // 调用构造函数
	Date d2(d1); // 调用拷贝构造函数

	system("pause");
	return 0;
}

这里是引用

② 还是Date类,未显式定义拷贝构造函数,编译器自动生成默认拷贝构造函数

class Date
{
public:
	Date(int year = 2000, int month = 4, int day = 21)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(2021, 4, 19);
	Date d2(d1);

	system("pause");
	return 0;
}

和上边的监视窗口中的内容一模一样这里是引用

2)当类中涉及到资源管理

例3:String类中,拷贝构造函数中使用malloc在堆上申请空间

① 未显式定义拷贝构造函数

class String
{
public:
	// 构造函数
	String(const char* str = "jia")
	{
		_str = (char*)malloc(strlen(str) + 1);
		strcpy(_str, str);
	}

	// 析构函数
	~String()
	{
		free(_str);
		_str = nullptr;
	}
private:
	char* _str;
};

// 当TestString函数执行完,s1、s2就要被销毁,这样可以看到销毁时调用析构函数的结果
// 如果直接写到main函数中,要return之后,对象才会被销毁,看不到调用析构函数的结果,需要将输出定向到文件中
void TestString()
{
	String s1("hello");
	String s2(s1);
}
int main()
{
	TestString();

	system("pause");
	return 0;
}

s1和s2中_str指向同一块内存空间
在这里插入图片描述

s1和s2中的_str变量的地址相同,这两个对象指向同一块内存空间。在这里插入图片描述
调用完TestString()函数后,s1和s2对象销毁时,会调用析构函数,先释放s2中的资源,可以看到s2指向的地址已经变成了空,而s1中访问的空间已经变成了无效访问
在这里插入图片描述
也就是说,此时堆上申请的空间已经被释放了,当s1调用析构函数再次free这段空间时,就会出错
在这里插入图片描述

② 显式定义拷贝构造函数

class String
{
public:
	// 构造函数
	String(const char* str = "jia")
	{
		// 从堆上开辟能保存字符串大小的一段空间,并将这段空间的首地址传给_str
		_str = (char*)malloc(strlen(str) + 1);
		// 将str字符串中的字符一个一个拷贝到_str指向的空间中
		strcpy(_str, str);
	}
	
	// 拷贝构造函数
	String(const String& s)
	{
		_str = (char*)malloc(strlen(s._str)+1);
		strcpy(_str, s._str);
	}

	// 析构函数
	~String()
	{
		cout << "~String()" << endl;
		free(_str);
		_str = nullptr;
	}
private:
	char* _str;
};

void TestString()
{
	String s1("hello");
	String s2(s1);
}
int main()
{
	TestString();

	system("pause");
	return 0;
}

s1中_str和s2中_str指向各自的内存空间
在这里插入图片描述

这次s2初始化时调用了显式定义的拷贝构造函数,我们在拷贝构造函数中给s2对象的_str在堆上新申请了一块空间,s1和s2各自拥有一段内存空间,所以s1和s2中_str中的地址不同
在这里插入图片描述
销毁对象时,调用析构函数free的时候,各自释放自己的那块空间,就不会出错了
在这里插入图片描述
结论:类中涉及到资源管理时一定要显式定义拷贝构造函数!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

类的默认成员函数【拷贝(复制)构造函数】 的相关文章

  • C++:如何检测向量中的重复项并打印一份副本?

    我是 C 新手 我想知道如何在向量中找到重复的字符串并打印出该字符串的一个副本 例如 如果我有它会打印出cat dog bird 我已经对我的向量进行了排序 并使用adjacent find函数并迭代该向量 因为我必须查找是否有任何单词重复
  • 在哪里使用 EF6 订阅 ObjectMaterialized?

    我正在尝试将我的上下文订阅到以下 OnjectMaterialized 事件this https stackoverflow com a 3756842 2835713 像这样 IObjectContextAdapter this Obje
  • 在列表中查找匹配项的最简洁方法

    在列表中查找内容的最佳方式是什么 我知道 LINQ 有一些不错的技巧 但我们也可以获取有关 C 2 0 的建议 让我们对这个常见的代码模式进行最佳重构 目前我使用这样的代码 mObjList is a List
  • ASP.NET 会员电子邮件验证

    尝试基于 C 创建电子邮件验证本文 https web archive org web 20211020153319 https www 4guysfromrolla com articles 062508 1 aspx 我创建了一个 ja
  • 在 C++ 中,std::string::push_back() 的摊余复杂度是 O(1) 吗?

    我知道标准指定它适用于向量 但是字符串呢 是的 它是摊销常数时间 请参见第 716 页的表 101本文件的 http www open std org jtc1 sc22 wg21 docs papers 2012 n3485 pdf 表
  • C/C++ 程序是在 CPU 上运行还是在内核上运行?

    我已经编程很多年了 但有一件事我一直不明白 有两种类型的编程语言 编译型语言和解释型语言 编译型语言首先需要编译成解释型语言 然后才能执行 例如 C C 需要先编译为机器语言 然后才能执行 我的问题来了 谁真正运行已编译的 C C Wind
  • 无法在表适配器配置属性中找到对象“Web.config”的连接“MyConnName”

    I want to change the query in table adapter but it s not opening throwing an error Configure table Adapter Failed in pro
  • Windows CE 6.0 和运行时链接到调试 DLL /MDd

    我在 x86 PC 上使用 Windows CE 6 0 R3 我已经为该平台构建了 NK bin 和 SDK 但我有一些问题需要了解如何使用 MTd 调试 DLL 构建控制台应用程序 如果我尝试构建这个 main c with MDd i
  • Visual Studio 2015 C# 找不到参考

    我在使用 Visual Studio 2015 和 C 时遇到了问题 在同一解决方案中添加对其他项目的引用时 Visual Studio 找不到所有类 例如 我创建了一个单元测试项目 我添加了对我创建的通信项目的引用 库中有 10 个类 但
  • 如何(可移植地)在 C 和 C++ 中获取 DBL_EPSILON

    我正在 Linux AS 3 上使用 GCC 3 4 并试图找出DBL EPSILON 或者至少是一个不错的近似值 我怎样才能以编程方式获取它 在 C 中是std numeric limits
  • 使用 Process.Start() 打开文件夹时访问被拒绝异常

    我有一个 C 中的 winforms 应用程序 我必须在其中打开某个文件夹 我用 System Diagnostics Process Start pathToFolder 这会导致以下异常 System ComponentModel Wi
  • 为什么我在这段代码中不断得到两个相同的随机值? [复制]

    这个问题在这里已经有答案了 可能的重复 为什么我的随机数生成器在 C 中不是随机的 https stackoverflow com questions 932520 why does it appear that my random num
  • DataContractJsonSerializer 包含元素类型子类型的通用列表

    我要使用DataContractJsonSerializer用于 JSON 序列化 反序列化 我在 JSON 数组中有两种对象类型 并希望将它们都反序列化为相应的对象类型 具有以下类定义 DataContract public class
  • Xamarin.Android JmDNS 绑定问题

    我开始研究 Xamarin Android 的 JmDNS 绑定 我设法构建了绑定 但无法从代码中引用它 https github com ytn3rd monodroid bindings tree master JmDNS https
  • 使用 Node.js 访问用 C++ 编写的 SDK

    我有一个用 C 语言编写的 SDK 可以与我的扫描仪设备进行通信 我需要开发一个可以访问扫描仪设备的电子应用程序 我知道有很多库可用于扫描仪 但我想使用这个 SDK 因为它允许我访问设备的完整功能 而且它是由设备制造商提供的 那么 有没有什
  • 在标准 C 中将 int 转换为 string

    我是 C 新手 我正在寻找一个可以调用函数进行转换的示例int串起来 我发现itoa但这不是标准 C 的一部分 我还发现sprintf str d aInt 但问题是我不知道所需的 str 的大小 因此 我如何传递输出字符串的正确大小 有多
  • 为什么 char 数组需要 strcpy 而 char star 不需要 - 在 C 中使用结构

    我对这段代码有一个误解 typedef struct EXP int x char name char lastName 40 XMP main XMP a a name eaaa a lastName strcpy a lastName
  • 使用 QTestLib 时抑制 qDebug

    我正在向 Qt 中的项目添加单元测试 并希望使用 QTestLib 我已经设置了测试并且它们运行良好 问题是在项目中我们重写了 qDebug 以输出到我们自己的日志文件 这在运行应用程序时效果很好 问题是当我测试类时 它有时会开始记录 然后
  • 使texture2D在运行时/脚本Unity3D中可读[重复]

    这个问题在这里已经有答案了 我有一个插件 可以让我访问 Android 手机图库中的图片 这给了我一个Texture2D类型的纹理 然后我想使用 GetPixels 函数对其进行编辑 但默认情况下它未设置为可读 如何使纹理可读 以便我可以在
  • C# 中的快速字符串解析

    在 C 中解析字符串最快的方法是什么 目前我只是使用字符串索引 string index 并且代码运行合理 但我忍不住认为索引访问器所做的连续范围检查必须添加一些东西 所以 我想知道我应该考虑哪些技术来增强它 这些是我最初的想法 问题 使用

随机推荐

  • oracle重复数据保留需要的一条数据

    由于功能开发进度的问题 人员录入的时候仅能够多次录入 不能够录入之后直接以该数据未蓝本引入导致多部门的时候必须多次创建冗余的数据 且由于数据录入的不规范 录入了许多相同的数据 特别是同单位同部门的数据 故需要处理此类数据 因此需要对此类重复
  • Unity --- 文本输入框的使用

    文本输入框有两个版本 一个是旧版的文本输入框 一个是新版的输入字段 这里选择旧版 其实旧版和新版的唯一区别就是text组件有些不同 其它的没啥不同 上面这两张图就是文本输入框中最重要的 input field 输入区域 组件的参数了 上面这
  • leetcode报错:member access within null pointer of type 'struct ListNode'

    背景 在编写判断单链表是否有环时 出现这错误 错误出现原因 错误出现原因 color Red text 38169 35823 20986 29616 21407 22240 因为试图使用空指针 解决方法 解决方法 color Red te
  • 音频模块的介绍

    一 术语总结 1 HIFI 级 HIFI 一词通常指高保真音频 High Fidelity Audio 是指尽可能保持音频信号的原始质量 让听众感受到最真实的音乐表现 因此 HIFI级 通常指具有高保真音频性能的产品或设备 例如高保真耳机
  • MAC使用Visual Studio Code开发C/C++

    MAC使用Visual Studio Code开发C C 一 前置概念 理解 二 环境准备 三 编译 运行 四 补充 一 前置概念 理解 VS code只是一个纯文本编辑器 editor 不是IDE 集成开发环境 不含编译器 compile
  • html天气插件iframe,分享常用7款天气预报代码iframe嵌入网页方式

    如果在网站上加入天气预报功能 你找不到更好的天气预报代码 可以看下本站和大家分享的7款天气预报代码iframe嵌入网页方式 天气预报代码1 src http appnews qq com cgi bin news qq search cit
  • python:pydub模块

    一 安装 1 安装模块 pip install pydub 2 安装插件 云盘中下载文件ffmpeg 打开电脑上的控制面板 系统 高级系统设置 环境变量 然后双击path 看到如下的界面 然后点新建会出现一个新建的地址栏 你需要在这个新建地
  • 备忘:maven 错误信息: Plugin execution not covered by lifecycle configuration

    在一个pom文件中 由于需要设置了一下几个默认goal的版本号 如下
  • 算法题:回文数

    力扣 思路 用栈 public static boolean isPalindrome int x if x lt 0 return false if x 0 return true 怎么取每位数字 String s String valu
  • 2023-DataWorks数仓开发手册收藏版

    DataWorks开发规范 1 数仓基本概念 1 4 1 ods数据源层表命名规范 1 4 2 dim维表层表命名规范 1 4 3 dwd数据明细层表命名规范 1 4 3 dws数据明细层表命名规范 1 4 4 ads数据应用层表命名规范
  • Docker从入门到精通

    目录 一 初识 Docker 1 Docker概念 2 安装Docker CentOS系统 3 Docker的架构 4 阿里云镜像加速 5 Docker容器虚拟化 与 传统虚拟机比较 二 Docker 服务相关命令 1 启动docker 服
  • 普通树转二叉树:左儿子右兄弟表示法

    这两天在吃力地学DP的优化 被虐地不行不行的 搞个小插曲 左儿子右兄弟 顾名思义 是一棵转换后的树 它是一棵二叉树 一个节点的左子树表示的是原树中这个节点的子节点 一个节点的右子树表示的是这个节点在原树中的兄弟 父节点相同的点 这么表示有什
  • 【机器学习】Reinforcement Learning-强化学习学习笔记

    一 强化学习的定义 1 1 什么是强化学习 首先 强化学习并不是某一种特定的算法 而是一类算法的统称 解决序列决策问题的一类方法 通过寻求最优策略 获取最大回报 强化学习就是智能体从环境到动作映射的学习 以使回报信号 激励信号 函数值最大
  • 在LINUX上安装Memcache服务器(实践记录)

    下载并安装Memcache服务器端 服务器端主要是安装memcache服务器端 下载 http www danga com memcached dist memcached 1 2 2 tar gz memcached 1 4 5 tar
  • Redux原理分析

    Redux原理分析 Redux是什么 很多人认为redux必须要结合React使用 其实并不是的 Redux 是 JavaScript 状态容器 只要你的项目中使用到了状态 并且状态十分复杂 那么你就可以使用Redux管理你的项目状态 它可
  • 如何卸载华为手机内置app

    作者 朱金灿 来源 clever101的专栏 为什么大多数人学不会人工智能编程 gt gt gt 最近自用的华为手机的存储空间快满了 想把手机内置的app清理一下 然后到网上搜索解决方案 大致弄明白了步骤 主要是通过华为手机内置APP卸载工
  • windows下cmd快速生成大文件命令

    fsutil file createnew 文件名 文件大小
  • C/C++中的头文件加上头文件中的ifndef/define/endif有什么作用?

    参考博客 https blog csdn net summer00072 article details 80883514 主要的作用就是防止头文件重复包含了 这个作用在Qt中是已经给你做好了 qt新建一个文件的时候就会直接给你建立完毕
  • Android结合ButterKnife创建自己的BaseActivity(兼容6.0)

    在Android开发中 我们需要创建一个BaseActivity来方便对APP中所有的activity进行统一操作 今天我们就来说说如何结合ButterKnife来打造一个加强版的BaseActivity 不熟悉ButterKnife的朋友
  • 类的默认成员函数【拷贝(复制)构造函数】

    拷贝 复制 构造函数 用一个已经存在的对象初始化另一个新对象时 编译器会自动调用拷贝构造函数 1 拷贝构造函数是构造函数的一种重载形式 2 拷贝构造函数的参数 单个形参 传递const类类型的引用 1 如果传值引用 会引发无穷调用 2 如果