首页 理论教育 C++复制构造函数合成方式掌握

C++复制构造函数合成方式掌握

时间:2023-08-20 理论教育 版权反馈
【摘要】:动手写9.1.3动手写9.1.3展示了编译器自动合成复制构造函数的行为。运行结果如图9.1.3所示:图9.1.3合成的复制构造函数MyClass的定义中没有声明任何复制构造函数,然而test()函数在传参和返回的时候需要复制构造函数,所以在这个时候编译器就会自动合成一个。运行结果如图9.1.4所示:图9.1.4浅复制我们可以看到,合成的复制构造函数对于指针只是简单地复制了地址,而两个对象中compPtr地址相同,指向的都是同一个对象。

C++复制构造函数合成方式掌握

由于存在着好几种自动隐式调用复制构造函数的情况,因此在没有编写自定义复制构造函数的时候,编译器也会自动合成出默认的复制构造函数。

动手写9.1.3

动手写9.1.3展示了编译器自动合成复制构造函数的行为。运行结果如图9.1.3所示:

图9.1.3 合成的复制构造函数

MyClass的定义中没有声明任何复制构造函数,然而test()函数在传参和返回的时候需要复制构造函数,所以在这个时候编译器就会自动合成一个。我们可以看到,myclass1()和test()的返回值的成员值完全一样,因此复制是成功的。

然而,我们也必须注意:系统合成的复制构造函数只能进行最基本的行为,也就是复制所有的成员;如果成员有类对象,就调用它的复制构造函数,或者合成一个。我们并不能完全依赖这样的函数,这是因为当类中有指针的时候,合成的复制构造函数只会复制指针的值,也就是地址,而不会复制指针指向的对象。

动手写9.1.4

动手写9.1.4展示了合成的复制构造函数对于指针的局限性。运行结果如图9.1.4所示:

图9.1.4 浅复制(www.xing528.com)

我们可以看到,合成的复制构造函数对于指针只是简单地复制了地址,而两个对象中compPtr地址相同,指向的都是同一个对象。这样不仅没有达到复制的效果,而且如果compPtr指向的对象是动态分配,系统在调用第二次析构函数的时候将会发现compPtr指向的对象已经被释放,从而发生异常。我们通常把这种仅仅复制指针地址的复制叫作浅复制。

有浅复制,那就必然有深复制。接下来就让我们看看如何使用自定义的复制构造函数来实现动态分配下的深复制。

动手写9.1.5

动手写9.1.5展示了深复制。运行结果如图9.1.5所示:

图9.1.5 深复制

我们可以看到,深复制的例子比浅复制的例子多了一个自定义的MyClass复制构造函数和析构函数。在这个函数中,对于comp我们还是调用了编译器给Component合成的复制构造函数;而对于compPtr来说,我们不再单纯地复制指针的地址,而是重新动态分配了一个新的Component,并在析构函数中释放。这种做法保证了compPtr指向的对象也是新的副本,在运行结果中它指向的地址也与要复制的对象中的不同,并且我们在由复制构造函数创建出的对象中独立管理了动态分配的内存。或许这两个例子还不能最直观地表现浅复制和深复制的区别,那我们来看一幅图:

图9.1.6 图解浅复制和深复制

我们可以看到,深复制真正做到了对象中所有成员的复制,我们可以在这之间画一条清晰的分隔线。而浅复制复制出的对象与之前的成员还有些藕断丝连,我们并不能将两者用线分隔开来。

最后,如果Component里也有指针,我们也需要重写Component的复制构造函数,原理与MyClass的类似。这个过程需要一直持续到没有指针的成员对象为止。

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

我要反馈