1. 程式人生 > 其它 >C++派生類的拷貝構造

C++派生類的拷貝構造

一. 概述

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

環境:Centos7 64位, g++ 4.8.5

在繼承中,構造器與析構器均沒有被繼承下來。拷貝構造,也是一種構造,也沒有被繼承下來。

父類中,一部分成員需要拷貝構造來完成,子類,也有一部分成員需要拷貝構造來完成。子類中的內嵌子物件中的成員也需要拷貝構造來完成。

二.實驗過程

1.無自實現(系統預設)

派生類中,不自實現拷貝建構函式,看下系統預設的拷貝構造情況。

基類A,派生類C繼承了基類A,派生類C中有一個內嵌子物件Bbb。

通過下面的執行情況,物件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++基礎與提高》 王桂林