【C++】深入剖析默认成员函数3:拷贝构造函数

上两篇博客我们深入探讨了一下另外两个默认成员函数:构造函数和析构函数。

他们两个都有一个特性:(1)对"内置类型"的成员函数:不进行初始化,也不进行清理(就是没有调用析构函数)。

(2)对于"自定义类型"的成员函数:会调用它对应的默认构造函数进行初始化,和对应的析构函数进行清理。

而今天我们迎来了第三问默认成员函数---拷贝构造函数!

听到"构造"两个字,想必大家马上就意识到这个宝贝构造函数跟构造函数有着微妙的关系吧?是的!

拷贝构造函数的概念:

  • 如果⼀个构造函数的第⼀个参数是⾃⾝类类型的引⽤,且任何额外的参数都有默认值,则此构造函数也叫做拷⻉构造函数,也就是说拷⻉构造是⼀个特殊的构造函数。(一般用const修饰)

当然,作为一个特殊的默认成员函数,同样也符合一下构造函数的特性:

  • 拷贝构造函数是构造函数的⼀个重载。
  • 拷贝构造函数的第⼀个参数必须是类类型对象的引用,使用传值方式编译器直接报错(否则就会无限递归调用)
  • 拷贝构造函数也可以多个参数,但是第⼀个参数必须是类类型对象的引用,后⾯的参数必须有缺省值。

代码实现如下:

cpp 复制代码
class Date
	 {
public:
	 Date(int year = 1, int month = 1, int day = 1)
		 {
		 _year = year;
		 _month = month;
		 _day = day;
		 }
	
		 // 编译报错:error C2652: "Date": ⾮法的复制构造函数: 第⼀个参数不应是"Date"
		 //Date(Date d)
		 Date(const Date & d)
	{
	     _year = d._year;
	     _month = d._month;
	     _day = d._day;
	}
		Date(Date* d)
	{
		_year = d->_year;
		_month = d->_month;
		_day = d->_day;
	}
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main() {
	Date d1(2024, 12, 22);
	//另外一种写法:d1(d2)
	Date d2 = d1;

	d1.Print();
	d2.Print();
	return 0;
}

运行结果:

运行结果就成功地将d1的值拷贝给d2啦!

当然,这里肯定还有一个问题:

为啥一定要使用引用传参呢?传值传参会怎么样吗?

那就让我们来验证一下:

运行结果:

简单来说,就是没有使用引用传参的话,就会形成无限递归传参,类似于套娃

而且,如果不需要改变参数,建议把const加上!

代码如下:

运行结果:

这才是正确的用法,否则就会引起编译器报错,奔溃.....

记住,只要你不需要改变函数体内容,就必须把const加上(别问为什么,因为跟我说一定要加上的人也没有说为什么)

默认的拷贝构造函数:

这里的默认拷贝构造函数就跟前面的构造函数和析构函数有所不同了

  • C++规定自定义类型对象进行拷贝行为必须调用拷贝构造,所以这里自定义类型传值传参和传值返回都会调用拷贝构造完成。
  • 若未显式定义拷贝构造,编译器会自动生成拷贝构造函数。⾃动⽣成的拷贝构造对内置类型成 员变量会完成值拷贝/浅拷贝(⼀个字节⼀个字节的拷贝),对⾃定义类型成员变量会调用他的拷贝构造。

代码实现如下:

cpp 复制代码
class Date
	 {
public:
	 Date(int year = 1, int month = 1, int day = 1)
		 {
		 _year = year;
		 _month = month;
		 _day = day;
		 }
	
		 // 编译报错:error C2652: "Date": ⾮法的复制构造函数: 第⼀个参数不应是"Date"
		 //Date(Date d)
	//	 Date(const Date& d)//使用引用传参
	//{
	//     _year = d._year;
	//     _month = d._month;
	//     _day = d._day;
	//}
		/*Date(Date* d)
	{
		_year = d->_year;
		_month = d->_month;
		_day = d->_day;
	}*/
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main() {
	Date d1(2024, 12, 22);
	//另外一种写法:d1(d2)
	Date d2 = d1;

	d1.Print();
	d2.Print();
	return 0;
}

运行结果:

相比于构造函数和析构函数,拷贝构造函数对内置函数和自定义函数都会进行处理

对于默认的拷贝构造函数,我们也不是完全就使用默认的,比如Stack类的,我们就需要自己实现拷贝,否则如果使用Stack st1拷贝出的Stack st2会指向同一个开辟的内存空间,这样就会导致析构指向的空间两次!

这样也就会导致程序报错,奔溃.....

以上就是对于拷贝构造函数的深入剖析

有问题希望佬们及时指出哦~

相关推荐
march_birds1 小时前
FreeRTOS 与 RT-Thread 事件组对比分析
c语言·单片机·算法·系统架构
小麦嵌入式1 小时前
Linux驱动开发实战(十一):GPIO子系统深度解析与RGB LED驱动实践
linux·c语言·驱动开发·stm32·嵌入式硬件·物联网·ubuntu
云 无 心 以 出 岫2 小时前
贪心算法QwQ
数据结构·c++·算法·贪心算法
jelasin2 小时前
LibCoroutine开发手记:细粒度C语言协程库
c语言
换一颗红豆2 小时前
【C++ 多态】—— 礼器九鼎,釉下乾坤,多态中的 “风水寻龙诀“
c++
篝火悟者2 小时前
自学-C语言-基础-数组、函数、指针、结构体和共同体、文件
c语言·开发语言
随便昵称3 小时前
蓝桥杯专项复习——前缀和和差分
c++·算法·前缀和·蓝桥杯
commonbelive3 小时前
团体程序设计天梯赛——L1-100 四项全能
c++
genispan3 小时前
QT/C++ 多线程并发下载实践
开发语言·c++·qt
小卡皮巴拉4 小时前
【力扣刷题实战】矩阵区域和
开发语言·c++·算法·leetcode·前缀和·矩阵