详解拷贝构造

拷贝构造的功能

写法:

拷贝构造函数的参数为什么是引用类型

系统自动生成的拷贝构造函数

拷贝构造的深拷贝与浅拷贝

概念

浅拷贝:

深拷贝

小结


拷贝构造的功能

拷贝构造函数 可以把曾经实例化好的对象的数据 拷贝给新创建的数据,可见说拷贝构造函数在功能上是构造函数的另一种形式。都是让对象初始化。

写法:

拷贝构造函数在语法层是构造函数的重载,函数名就是类名,无返回值,参数是该类类型对象的引用(为了保护被引用对象数据不被破坏,会在类型前面加上const)

cpp 复制代码
 Date(const Date& d) //以日期类为例,定义拷贝构造的写法
cpp 复制代码
Date d1;
 Date d2(d1); //以日期类为例,实例化对象时的写法

拷贝构造函数的参数为什么是引用类型

下面是定义的日期类的拷贝构造函数,但参数并不是引用类型

cpp 复制代码
Date(const Date d)
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
}

因为是传值,实例化对象时需要调用拷贝构造函数把数据拷贝过来,但拷贝数据函数的参数又需要掉用拷贝构造函数 ,如此就死循环了,拷贝构造函数会被无限调用。如图所示这种情况编译器会强制报错

系统自动生成的拷贝构造函数

若未显式定义,编译器会生成默认的拷贝构造函数 默认的拷贝构造函数对象按内存存储 按字节序 完成拷贝,这种拷贝叫做浅拷贝 ,或者值拷贝
下面代码中定义了一个时间类 Time ,又定义了一个日期类 Date , 时间类在日期类里实例化了对象_t,_t就是日期类的自定义类型,但并没有定义日期类的拷贝构造函数。那么系统自动生成的拷贝构造函数会怎么处理自定义类型_t和内置类型的年月日呢?

cpp 复制代码
class Time {   //时间类
public:

Time() 
   {
_hour = 1;
_minute = 1;
_second = 1;
}

Time(const Time& t) //自定义时间类的拷贝构造函数
{
_hour = t._hour;
_minute = t._minute;
_second = t._second;
}

private:

int _hour;
int _minute;
int _second;
};

class Date  //日期类,但没有自定义拷贝构造函数
{
	
private:
// 基本类型(内置类型)
	int _year;
	int _month;
	int _day;

// 自定义类型
Time _t;  //时间类实例化对象 _t
	
};

int main(){

Date d1;
Date d2(d1); //拷贝对象d1的数据

 // 用已经存在的d1拷贝构造d2,此处会调用Date类的拷贝构造函数
    // 但Date类并没有显式定义拷贝构造函数,则编译器会给Date类生成一个默认的拷贝构造函数

return 0;
}

只需明晰一点即可,系统自动生成的默认拷贝构造对内置类型进行浅拷贝,对自定义类型,会调用自定义类型的拷贝构造函数,若自定义类型并未定义拷贝构造函数,系统便会自动生成。

下图是代码执行示意图

下图是逻辑示意图

拷贝构造的深拷贝与浅拷贝

概念

浅拷贝:

又称值拷贝,是按字节序拷贝的,通俗的讲别的数据长啥样就拷贝啥样。

浅拷贝的细节:下面代码中还是定义了一个日期类,但增加了一个int*的变量它指向一块空间。这是让默认构造函数进行浅拷贝会发生什么呢?

cpp 复制代码
class Date //日期类,并没有定义拷贝构造函数
{
public:

	Date()//构造函数
	{
		_year = 1;
		_month = 1;
		_day = 1;
			_a = (int*)malloc(sizeof(int) * 7); //开辟空间并把空间的值初始化
			for (int i = 0; i < 7; i++)
			{
				_a[i] = 0;
			}
	}

private:
	int _year;
	int _month;
	int _day;
	int* _a; //指向一块空间
};
int main()
{
	Date d; 
	Date d1(d); //拷贝d的值
}

结果:d对象和d1对象的数据会一模一样,如下图

我们发现d对象的值和d1对象的值一模一样,并且d对象中的_a和d1对象中的_a都指向同一块空间。如下图

上述就值浅拷贝的坏处,d1对象的_a并没有申请资源而是直接指向了d对象_a的空间,如果想让d1

_a也申请空间就需要深拷贝,想要深拷贝就需要自己定义一个拷贝构造函数,该拷贝构造函数如何申请空间要根据不同的场景具体实现。

深拷贝

下面的代码是对上面代码的改造,

cpp 复制代码
class Date
{
public:

	Date() //构造函数
	{
		_year = 1;
		_month = 1;
		_day = 1;
			_a = (int*)malloc(sizeof(int) * 7);
			for (int i = 0; i < 7; i++)
			{
				_a[i] = 0;
			}
	}

	Date(const Date& d) //拷贝构造函数
	{
		_year = d._year; 
		_month = d._month;
		_day = d._day;

		_a = (int*)malloc(sizeof(int) * (sizeof(d._a) / sizeof(d._a[0])));  //开辟空间

			for (int i = 0; i < (sizeof(d._a) / sizeof(d._a[0])); i++)  //赋值
			{
				_a[i] = d._a[i];
			}
	}

private:
	int _year;
	int _month;
	int _day;
	int* _a;
};
int main()
{
	Date d;
	Date d1(d);
}

d1对象的_a会独自开空间并且拷贝d对象的数据,如下图这样就完成了拷贝构造的深拷贝了。

小结

拷贝构造是构造函数的重载 。参数是该类类型的引用 (一般会加上const),不加引用在逻辑是会让拷贝函数无限调用,此时编译器会报错。如果未显示定义拷贝构造函数,编译器会生成默认的拷贝构造函数**。默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝** ,或者值拷贝。浅拷贝又称值拷贝,是按字节序拷贝的,通俗的讲别的数据长啥样就拷贝啥样。而深拷贝会申请资源(空间)再赋值。

另外我还为大家准备了几篇不错的博客

构造函数: http://t.csdnimg.cn/MdHiA

希尔排序: http://t.csdnimg.cn/uxSBG

堆排序的时间复杂度: http://t.csdnimg.cn/OJLzI

相关推荐
一个没有本领的人3 分钟前
win11+matlab2021a配置C-COT
c语言·开发语言·matlab·目标跟踪
anyup_前端梦工厂8 分钟前
初始 ShellJS:一个 Node.js 命令行工具集合
前端·javascript·node.js
5hand12 分钟前
Element-ui的使用教程 基于HBuilder X
前端·javascript·vue.js·elementui
一只自律的鸡26 分钟前
C项目 天天酷跑(下篇)
c语言·开发语言
源码哥_博纳软云29 分钟前
JAVA智慧养老养老护理帮忙代办陪诊陪护小程序APP源码
java·开发语言·微信小程序·小程序·微信公众平台
GDAL30 分钟前
vue3入门教程:ref能否完全替代reactive?
前端·javascript·vue.js
沐泽Mu32 分钟前
嵌入式学习-QT-Day05
开发语言·c++·qt·学习
小板凳-BGM44 分钟前
C# 第二阶段 modbus
开发语言·ui·c#
许野平1 小时前
Rust: enum 和 i32 的区别和互换
python·算法·rust·enum·i32
问道飞鱼1 小时前
【Python知识】Python进阶-什么是装饰器?
开发语言·python·装饰器