理论教育 浅拷贝与深拷贝的差别

浅拷贝与深拷贝的差别

时间:2023-10-25 理论教育 版权反馈
【摘要】:图3-1无拷贝构造运行结果图在默认的拷贝构造函数中,拷贝的方式是逐个成员信息依次拷贝,新对象的数据成员信息与被拷贝对象的数据信息完全一样,这种拷贝方式称为浅拷贝。首先使用系统提供的默认拷贝构造函数实现浅拷贝,观察结果,然后使用深拷贝方式实现拷贝。

浅拷贝与深拷贝的差别

在例3.1中,如果把拷贝构造函数删除,使用系统提供的默认拷贝构造函数,那么能行吗?当把拷贝构造函数删除,编译程序通过,但执行时,却出现了问题,程序的运行效果如图3-1所示。

为什么在例3.2中可以使用默认的拷贝构造函数,而例3.1中却不能使用默认的拷贝构造函数呢?它们有什么区别呢?

图3-1 无拷贝构造运行结果图

在默认的拷贝构造函数中,拷贝的方式是逐个成员信息依次拷贝,新对象的数据成员信息与被拷贝对象的数据信息完全一样,这种拷贝方式称为浅拷贝。如果被拷贝对象有使用系统的资源(如堆内存),在这种情况下,新对象也将使用和被拷贝对象相同的资源,当其中一个对象被析构时,释放资源,那么另一对象将会发生无法使用资源的情况,也就发生了运行错误,如在例3.1中使用默认拷贝构造函数时,系统运行出现非法使用堆指针的错误。程序运行到析构对象s1时,正常析构,把堆空间释放,在析构对象s2时,由于堆空间已经释放,所以读取name时,显示错误信息“葺葺葺葺”,执行delete操作时,弹出对话框显示错误信息。

定义拷贝构造函数,在函数内把被拷贝对象的资源信息也同样拷贝一份给新对象,使新对象有自己的资源,这种方式称为深拷贝。对于例3.1,在拷贝构造函数中,给新对象也分配了堆空间,s1对象和s2对象各自有自己的堆空间,在析构时都能释放各自的空间,不会出现运行错误。

在例3.2中,Person类中name属性的类型是字符数组,使用默认拷贝构造,拷贝对象和被拷贝对象都有各自的数据内存空间,不会出现共用资源的情况,所以使用默认拷贝构造就可以正常运行。而例3.1中,Student类的name和no属性都是字符指针类型,需要使用堆空间存放字符串信息,也就是对象需要使用资源,需要自定义拷贝构造函数,为新对象分配资源。

在C++中,若对象在运行过程中需要使用资源(如使用堆内存、打开文件、使用打印机等)时,程序需要添加拷贝构造函数,进行深拷贝,同时也需要定义析构函数释放资源。一般不使用资源的情况下,使用浅拷贝方式即可。

在C++中,系统提供的默认拷贝构造函数,是一个成员一个成员的拷贝,如果成员是类对象,则调用其自定义拷贝构造函数或默认拷贝构造函数。

【例3.3】设计教师类,数据成员有姓名和简介,其中简介是备注类类型,姓名为字符数组类型,成员函数有输出信息和构造函数。备注类数据成员有内容和教龄,其中内容类型为字符指针类型,成员函数有构造函数、拷贝构造函数、析构函数、取得内容、取得教龄等。

在例3.3中,Teacher类中没有额外使用系统资源,不需要添加拷贝构造函数,浅拷贝方式即可,而在Memo类中,数据成员content是字符指针,存放数据信息需要使用堆空间,此时需要添加拷贝构造函数实现资源的深拷贝。

综合实训

拷贝构造函数

【实训目的】

1.了解拷贝构造函数的定义。

2.深入理解浅拷贝和深拷贝。

3.灵活运用拷贝构造函数。

【实训内容】

设计一个可变大小的数组类,可根据传递的数组和大小创建数组类,数组类的数据成员有存放数据的头指针和数组大小。在main函数创建一个数组对象,然后用这个对象去初始化另一个对象。首先使用系统提供的默认拷贝构造函数实现浅拷贝,观察结果,然后使用深拷贝方式实现拷贝。

【实训设计】

浅拷贝使用默认的拷贝构造函数实现,参考代码如下:

此程序在运行时会出错,主要是由于浅拷贝方式,second Array对象没有自己的资源空间,两个对象的head指针的值相同,堆内存资源两个对象共用,在first Array对象析构后,second Array对象的head 指针所指向的空间就是非法的内存空间了。修改此程序,在Array类中添加拷贝构造函数,再运行程序。添加的代码参考如下。

添加拷贝构造函数后,再运行程序,结果如下:

(www.daowen.com)

项目小结

C++中系统提供的默认拷贝构造函数可以实现对象的浅拷贝复制,如果对象的数据成员需要额外使用系统资源,如堆空间、文件或打印机等时,则需要添加自定义的拷贝构造函数,进行深拷贝,为新对象分配资源并拷贝信息。

课后练习

一、选择题

1.下面关于拷贝构造函数描述正确的是( )。

A.拷贝构造函数可以有多个参数

B.拷贝构造函数的参数是该类对象的引用

C.拷贝构造函数必须需要显示调用

D.系统不提供默认的拷贝构造函数

2.类Person的拷贝构造函数的原型是( )。

A.Person(); B.Person(char∗p);

C.Person(const Person&p); D.Person(Person p);

3.下面不是拷贝构造函数的调用时机( )。

A.用一个已存对象初始化一个新对象

B.把对象作为值参数传递给函数

C.把对象作为函数的返回值

D.把对象作为引用参数传递给函数

4.下面描述正确的是( )。

A.类中必须定义拷贝构造函数

B.系统提供的默认拷贝构造函数只实现数据成员的逐一拷贝

C.系统提供的默认拷贝函数能实现深拷贝

D.浅拷贝方式能实现资源的再分配和拷贝

5.在把对象作为形式参数传递给函数时,系统调用( )。

A.无参构造函数 B.析构函数

C.拷贝构造函数 D.默认参数的构造函数

二、编程题

1.定义一个员工类Employee,该类中的数据成员有:员工编号、姓名、员工部门,其中姓名、员工部门使用字符指针类型,员工编号使用整型。该类中的成员函数有:构造函数、析构函数、拷贝构造函数和打印员工信息等。要求在main函数中,创建该类对象,并使用拷贝构造函数。

资源推荐

1.C++网站 http://www.cplusplus.com

2.C++类库参考 https://msdn.microsoft.com/zh-cn/library/cscc687y.aspx

3.百度传课 http://www.chuanke.com/course/72351176561000448______2.html

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈