C++派生类的拷贝构造

一. 概述

通过几个简单的实验,回顾下派生类中拷贝构造的相关知识。

环境:Centos7 64位, g++ 4.8.5

 

在继承中,构造器与析构器均没有被继承下来。拷贝构造,也是一种构造,也没有被继承下来。

父类中,一部分成员需要拷贝构造来完成,子类,也有一部分成员需要拷贝构造来完成。子类中的内嵌子对象中的成员也需要拷贝构造来完成。

 

二. 实验过程

1.无自实现(系统默认)

派生类中,不自实现拷贝构造函数,看下系统默认的拷贝构造情况。

 基类A,派生类C继承了基类A,派生类C中有一个内嵌子对象B bb。

 

通过下面的运行情况,对象c2拷贝了c1,派生类中调用了父类中默认的拷贝构造函数,内嵌子对象也是一样。

 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 class A
 6 {
 7     public:
 8         A(int x = 10)
 9             :a(x)
10         {
11             cout<<"constructor A()"<<endl;
12         }
13 
14         int a;
15 };
16 
17 class B
18 {
19     public:
20         B(int y = 20)
21             :b(y)
22         {
23             cout<<"constructor B()"<<endl;
24         }
25 
26         int b;
27 };
28 
29 class C: public A
30 {
31     public:
32         C(int x, int y, int z = 30)
33             :A(x), bb(y)
34         {
35             c = z;
36             cout<<"cosntructor C()"<<endl;
37         }
38 
39         int c;
40         B bb;
41 };
42 
43 int main()
44 {
45     C c1(42, 21, 14);
46     cout<<"c1: "<<c1.a<<" "<<c1.bb.b<<" "<<c1.c<<endl;
47 
48     cout<<"----------"<<endl;
49     C c2(c1);
50     cout<<"c2: "<<c2.a<<" "<<c2.bb.b<<" "<<c2.c<<endl;
51 
52     return 0;
53 }

运行结果如下:

 

达到了预期结果。

c2成功地拷贝了c1。根据打印结果,可知,c1对象在生成时,先调用了基类A的构造函数,然后是内嵌子对象bb的构造函数,最后是C自己的构造函数。

 

 2.派生类中自实现拷贝构造函数,不显示调用父类、内嵌子对象中的拷贝构造函数

派生类C中,自实现拷贝构造函数,第11行-第14行,如下。

通过打印结果发现,派生类调用了基类的构造函数,而不是默认的拷贝构造函数。内嵌子对象也是一样。

对象c1和c2中的两个成员a, b结果均不一致,也就是说父类和内嵌子对象中的成员都没有被拷贝过来,c2中的a、b的值是父类、内嵌子对象中调用构造函数进行初始化而来的。此时,拷贝构造也没有什么意义了。无法达到拷贝的效果。

 1 class C: public A
 2 {
 3     public:
 4         C(int x, int y, int z = 30)
 5             :A(x), bb(y)
 6         {
 7             c = z;
 8             cout<<"cosntructor C()"<<endl;
 9         }
10 
11         C(const C &another)
12         {
13             c = another.c;
14         }
15 
16         int c;
17         B bb;
18 };

运行结果如下:

 

 

3.派生类中自实现拷贝构造,显示调用父类、内嵌子对象中的拷贝构造函数

 派生类C中添加显示调用,第12行代码。

注:A(another),将派生类对象赋值给父类的引用,用到了赋值兼容。

此时,派生类中的拷贝构造函数调用了基类中默认的拷贝构造函数。此时,浅拷贝也可以满足需求(关于浅拷贝与深拷贝)。

 1 class C: public A
 2 {
 3     public:
 4         C(int x, int y, int z = 30)
 5             :A(x), bb(y)
 6         {
 7             c = z;
 8             cout<<"cosntructor C()"<<endl;
 9         }
10 
11         C(const C &another)
12             :A(another), bb(another.bb)
13         {
14             c = another.c;
15         }
16 
17         int c;
18         B bb;
19 };

运行结果如下:

 运行结果符合预期,实现了拷贝的目的。

 

 4.在3的基础上,如果需要实现深拷贝的目的,则父类中也需要自实现拷贝构造

类A,增加第10行-第14行代码

 1 class A
 2 {
 3     public:
 4         A(int x = 10)
 5             :a(x)
 6         {
 7             cout<<"constructor A()"<<endl;
 8         }
 9 
10         A(const A &another)
11         {
12             a = another.a;
13             cout<<"A(const A &another)"<<endl;
14         }
15 
16         int a;
17 };

类B,增加第10行-第14行代码

 1 class B
 2 {
 3     public:
 4         B(int y = 20)
 5             :b(y)
 6         {
 7             cout<<"constructor B()"<<endl;
 8         }
 9 
10         B(const B &another)
11         {
12             b = another.b;
13             cout<<"B(const B &another)"<<endl;
14         }
15 
16         int b;
17 };

运行结果如下:

根据打印结果可知, 对象c2在拷贝c1时,调用了基类和内嵌子对象的拷贝构造函数。

 

四. 总结

当派生类中不自实现拷贝构造时,默认调用父类的拷贝构造函数;

当派生类中自实现拷贝构造时,不做特殊处理(显示地调用父类的拷贝构造函数,包括系统默认和自实现拷贝构造函数),此时,只会调用父类的构造函数。此时,也失去了拷贝的意义,无法实现拷贝;

当派生类自实现拷贝构造,进行特殊处理(显示地调用父类的拷贝构造函数,包括系统默认和自实现的拷贝构造函数),此时,会调用父类的拷贝构造函数。

内嵌子对象与上面类似。

 

参考材料:

《C++基础与提高》  王桂林

posted @ 2021-08-01 15:59  bruce628  阅读(757)  评论(0编辑  收藏  举报