C++:类的6大默认成员函数(拷贝构造函数篇)

文章目录

  • 1、拷贝构造函数的概念
    • const用途
  • 2、拷贝构造函数的特性
    • 浅拷贝/值拷贝

前言:Hello,大家好,咱这篇博客继续默认成员函数,今天的笔记分享为拷贝构造函数~

1、拷贝构造函数的概念

在创建对象时,我们能否创建一个与已存在对象一某一样的新对象呢?
答案是可以的,让我们一起来看看吧。

首先我们先定义一个Date类:

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

	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

	Date(Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

private:
	int _year;
	int _month;
	int _day;

};

int main()
{
	Date d1(2024, 1, 28);
	Date d2(d1);

	return 0;
}

拷贝构造函数::只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。 像上述Date类中所含的拷贝构造函数:

Date(Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

上述拷贝构造函数我们也可以写成(加上this指针):

const用途

Date(Date& d)
	{
		this->_year = d._year;
		this->_month = d._month;
		this->_day = d._day;
	}

当然了,一般情况下,我们还会加上const修饰:

Date(const Date& d)

正常情况下,加不加const无所谓,加上的目的主要是防止我们有时候写代码迷糊了,将构造函数写成如下形式:

d._year= this->_year;
d._month=this->_month ;
d._day=this->_day ;

这种情况相当于"逆拷贝",我们通过拷贝d2来改变d1,本末倒置。

在这里插入图片描述
const的出现就是为了避免此类"昏头行为",加上之后,当我们写反了编译器就会报错,我们就可以马上纠正了。

2、拷贝构造函数的特性

拷贝构造函数也是特殊的成员函数,其特性为:
a.拷贝构造函数是构造函数的一个重载形式(拷贝构造函数是构造函数的一种);

b.拷贝构造函数的参数只有一个且必须是类型为类的对象的引用,使用传值方式编译器直接报错(因为会引发无穷递归调用);
对于传值传参和传引用传参,我们通常作以下解释:

解释1.C++传值传参时需要调用拷贝构造函数:
在这里插入图片描述
解释2.但是传引用传参时,就不需要调用拷贝构造函数了,此时的rd就是d1的别名。
在这里插入图片描述

延伸3.对于以下这个拷贝构造函数,如果我们将它改为传值调用,会发生什么情况呢?

Date(Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

调用拷贝构造函数要先传参,而根据解释1,传值传参时需要调用拷贝构造函数,而且传值传参时会形成一个新的拷贝构造函数,不断调用,不断生成,最终会引发无穷递归
也正因为如此,我们拷贝构造函数的参数必须是类型为类的对象的引用
在这里插入图片描述

浅拷贝/值拷贝

c. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按
字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝

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

	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
	

private:
	int _year;
	int _month;
	int _day;

};

int main()
{
	Date d1(2024, 1, 28);
	Date d2(d1);
	d1.Print();
	d2.Print();
	return 0;
}

在这里插入图片描述
这里我没写拷贝构造函数,但这里可以看出自动拷贝,也可以说明默认生成的拷贝构造函数对内置类型同样处理了(不同于构造、析构函数)。
d.编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了,还需要自己显式实现吗?

当然像日期类这样的类是没必要的。但下面的类呢?让我们一起来看看吧。

typedef int DataType;
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:
 DataType *_array;
 size_t _size;
 size_t _capacity;
};
int main()
{
 Stack s1;
 s1.Push(1);
 s1.Push(2);
 s1.Push(3);
 s1.Push(4);
 Stack s2(s1);
 return 0;
}

在这里插入图片描述
s2对象是s1使用拷贝构造,而此时Stack没有显示定义拷贝构造函数,所以s1中的内容会原封不动地拷贝到s2,此时就会出现一个问题:s1,s2指向了一个内存空间,当程序退出时,s1,s2都会调用析构函数来销毁,这就导致了一块内存空间会被释放两次,必将造成程序崩溃。

总结(重要):类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请时,则拷贝构造函数是一定要写的,否则就是浅拷贝。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C/C++代码性能优化——数据结构和算法

1. 数据结构 合适的数据结构&#xff0c;对代码的性能提升非常明显。针对数据结构&#xff0c;我们不需要可以做到白板手写的程度。只要熟知其特点&#xff0c;然后推导出其应用场景&#xff0c;等到了真正需要时&#xff0c;再查找示例代码来修改应用即可。 1.1. 数组 固定…

Nginx离线安装(保姆级教程)

1、下载与安装gcc-c环境 获取rpm包的方式很多&#xff0c;在这里推荐使用yum工具获取&#xff0c;因为手动从官网下载&#xff0c;手动执行rpm -Uvh *.rpm --nodeps --force命令进行安装&#xff0c;可能会缺少某个依赖&#xff0c;我们也不确定到底需要哪些依赖。 因此需要准…

Java毕业设计 基于springboot医院挂号系统 医院管理系统

Java毕业设计 基于springboot医院挂号系统 医院管理系统 springboot医院挂号系统 医院管理系统 功能介绍 用户&#xff1a;登录 首页 个人资料 修改密码 门诊管理 用户挂号 医生&#xff1a;登录 首页 个人资料 修改密码 门诊管理: 用户挂号 处方划价 项目划价 项目缴费 项目…

【机器学习300问】43、回归模型预测效果明明很好,为什么均方根误差很大?

一、案例描述 假设我们正在构建一个房地产价格预测模型&#xff0c;目标是预测某个城市各类住宅的售价。模型基于大量房屋的各种特征&#xff08;如面积、地段、房龄、楼层等&#xff09;进行训练。 回归模型在大部分情况下对于住宅价格预测非常精准&#xff0c;用户反…

【教程】深入探究 JS代码混淆与加密技术

&#x1f512; 引言 在网络世界中&#xff0c;保护代码安全是至关重要的一环。JS代码混淆与加密技术则成为了开发者们常用的手段之一。本文将深入探讨混淆和加密的概念&#xff0c;以及其实现原理和应用方法&#xff0c;帮助读者更好地了解并运用这些技术。 ✨ 概念介绍 &quo…

调用百度通用翻译API进行中文翻译(附python代码)

文章目录 1. 百度API2. API接口3. 大规模使用4. AcknowledgmentReference彩蛋&#xff1a;百度大脑 AI开放平台 1. 百度API 在百度翻译开放平台&#xff08;http://api.fanyi.baidu.com/api/trans/product/desktop&#xff09;注册账号&#xff0c;可以免费使用基本版翻译功能…

C语言复杂度(个人笔记)

时间复杂度主要衡量一个算法的运行快慢. 空间复杂度主要衡量一个算法运行所需要的额外空间. 时间复杂度 算法中的基本操作的执行次数&#xff0c;为算法的时间复杂度. 只需要大概执行次数&#xff0c;我们使用大O的渐进表示法。(看谁对数学表达式的影响最大) 空间复杂度 是…

论文笔记:Contrastive Multi-Modal Knowledge GraphRepresentation Learning

论文来源&#xff1a;IEEE Transactions on Knowledge and Data Engineering 2023 论文地址&#xff1a;Contrastive Multi-Modal Knowledge Graph Representation Learning | IEEE Journals & Magazine | IEEE Xplorehttps://ieeexplore.ieee.org/abstract/document/9942…

可变形卷积颠覆式创新!新SOTA提速80%,更高性能,更强几何适应能力

在传统的卷积神经网络中&#xff0c;固定模式的卷积核在处理图像时可能会限制网络对不规则形状特征的提取能力。为了解决这个问题&#xff0c;研究者提出了可变形卷积。 可变形卷积是一种改进的卷积操作&#xff0c;它通过引入可学习的偏移量来增强模型对几何变化的适应能力&a…

qt+ffmpeg 实现音视频播放(三)之视频播放

一、视频播放流程 &#xff08;PS&#xff1a;视频的播放流程跟音频的及其相似&#xff01;&#xff01;&#xff09; 1、打开视频文件 通过 avformat_open_input() 打开媒体文件并分配和初始化 AVFormatContext 结构体。 函数原型如下&#xff1a; int avformat_open_inpu…

python 教你如何创建一个自定义库 colorlib.py

目录 Colorlib 生成代码 模块代码 导入测试 测试一 测试二 应用测试 颜色列表 colorList 随机颜色元组 randcolorTuples 随机颜色字串 randcolorStrings Color类测试 测试一 测试二 题外话 Colorlib 有没有碰到过这样的场景&#xff1a;写代码时想要用上丰富的色…

C#混淆心得

C#混淆心得 近期遇到混淆C#代码的需求&#xff0c;在网上找了很多办法&#xff0c;在此记录一下。 混淆的本质就是让代码变丑&#xff0c;让别人看不懂。 为什么要混淆&#xff1a; 1.保护核心代码 可以在一定程度上避免别人偷代码&#xff0c;从而保护重要的部分&#xf…

3.3 RK3399项目开发实录-板载Ubuntu系统的使用(wulianjishu666)

嵌入式物联网常用90款传感器开发例程。链接&#xff1a;https://pan.baidu.com/s/1oisHMZXDzKqa4EspY83V-A?pwdo5f4 1. 介绍 Ubuntu 使用手册是针对 Firefly 官方发布的 Ubuntu 系统固件特性所编写&#xff0c;适用于 Ubuntu Desktop 与 Minimal 系统&#xff0c;部分与 UI 显…

适用于智能语音小家电的语音ic类型有哪些?

适用于智能语音小家电的语音ic类型有哪些&#xff1f; 1. 语音播放芯片&#xff1a;这种芯片主要用于实现语音提示和报警功能。例如&#xff0c;当按下某个按钮时&#xff0c;它可以发出语音提醒&#xff0c;或者在出现故障时发出报警声音。这种芯片的应用非常广泛&#xff0…

Halcon 条码读取

一维码读取 create_bar_code_model 创建条码读取器的模板 set_bar_code_param 配置解码方式 find_bar_code 读取条码 clear_bar_code_model 清除条码匹配模板 * 1.创建条码读取器的模板 * 参数一&#xff1a;通用参数的名称&#xff0c;针对条形码模型进行调整。默认值为空 * 参…

Java实用经验总结

前言&#xff1a;以下为笔者在工作中总结的好用且简洁代码的经验 文章目录 1、多判断代替if2、通配符替换内容&#xff08;常见于邮件、短信等模版&#xff09;3、spring获取bean对象4、动态获取nacos配置5、优雅校验请求入参 1、多判断代替if 针对多个是和否的问题&#xff0…

如何安装和卸载SFP光模块

SFP光模块的安装和拆卸是简单直接的过程。然而&#xff0c;任何非标准操作都可能导致隐式损坏甚至永久故障。您需要参考及时更新的光模块的数据表或用户手册&#xff0c;以熟悉其特性和锁定机制。 准备工作 常见事项 拆卸和插入SFP光模块可能会缩短其使用寿命&#xff0c;因…

搜索二维矩阵

题目链接 搜索二维矩阵 题目描述 注意点 每行中的整数从左到右按非严格递增顺序排列每行的第一个整数大于前一行的最后一个整数1 < matrix.length, matrix[0].length < 100 解答思路 先二分查找找到target所处的行&#xff0c;找到行后再二分查找找到target所处的列…

Java毕业设计-基于springboot开发的数码论坛系统设计与实现-毕业论文+答辩PPT(附源代码+演示视频)

文章目录 前言一、毕设成果演示&#xff08;源代码在文末&#xff09;二、毕设摘要展示1、开发说明2、需求分析3、系统功能结构 三、系统实现展示1、系统功能模块2、管理员功能模块3、用户后台管理模块 四、毕设内容和源代码获取总结 **Java毕业设计-基于springboot开发的数码论…

计算平均分 javascript

养成好习惯&#xff1a;先写注释再写代码 基础版&#xff1a;直接写逻辑&#xff08;平均分总和/个数&#xff09; // 求平均分 var scores [60, 55, 80, 33, 75, 100]; // 求和,相除 var sum 0; var avg;for (var i 0; i < 6; i) {sum scores[i]; }avg sum / 6; con…