C++派生類的拷貝構造

bruce628發表於2021-08-01

一. 概述

通過幾個簡單的實驗,回顧下派生類中拷貝構造的相關知識。

環境: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++基礎與提高》  王桂林

相關文章