【C++ Primer 第15章】定義派生類拷貝構造函數、賦值運算符

學習資料

派生類的賦值運算符/賦值構造函數也必須處理它的基類成員的賦值html

• C++ 基類構造函數帶參數的繼承方式及派生類的初始化ios

 

定義拷貝構造函數

【注意】對派生類進行拷貝構造時,若是想讓基類的成員也同時拷貝,就必定要在派生類拷貝構造函數初始化列表中顯示調用基類拷貝構造函數(固然在函數體內將基類部分的值拷貝也是能夠的,只不過它是先用默認構造函數初始化後再修改的基類成員變量的值,效率比較低),不然它會調用基類的默認構造函數,而不會對基類的成員變量拷貝值,這樣生成的對象,它的派生類部分和被拷貝的對象派生類部分同樣,而基類部分則是默認構造函數的初始化結果。app

代碼例子1:函數

 1 #include <iostream>
 2 using namespace std;  3 
 4 class A  5 {  6 public:  7     A() { cout << "A default constructor" << endl; }  8     A(A&) { cout << "A copy constructor" << endl; }  9 }; 10 class B : public A 11 { 12 public: 13     B() { cout << "A default constructor" << endl; } 14     B(B &b) { cout << "B copy constructor" << endl; } 15 }; 16 
17 int main() 18 { 19  B b; 20     B c = b; 21     return 0; 22 }

輸出結果:學習

 

 

代碼例子2:this

 1 #include <iostream>
 2 using namespace std;  3 
 4 class A  5 {  6 public:  7     A() { cout << "A default constructor" << endl; }  8     A(A&) { cout << "A copy constructor" << endl; }  9 }; 10 class B : public A 11 { 12 public: 13     B() { cout << "A default constructor" << endl; } 14     B(B &b) : A(b) { cout << "B copy constructor" << endl; } 15 }; 16 
17 int main() 18 { 19  B b; 20     B c = b; 21     return 0; 22 }

輸出結果:spa

 

 

C++ 基類構造函數帶參數的繼承方式及派生類的初始化.net

在定義類的時候,會遇到基類的構造函數帶參數,而子類子類構造函數不帶參數,這時候若是以代碼 a 的方式創建派生類則會出錯。code

 1 class A  2 {  3     public:  4         A(int x, int y): i(x), j(y) {}  5     private:  6         int i, j;  7 };  8 
 9 class B : public A 10 { 11     public: 12         B() { cout << "init B" << endl; } 13 };

在創建B類對象時,編譯出錯: 
 C:\Documents and Settings\admin\桌面\Text1.cpp(104) : error C2512: ‘A’ : no appropriate default constructor available htm

 

解決這個問題應該在A的構造函數中顯式調用基類的帶參構造函數。由於在基類中定義了帶參構造函數,編譯器不會提供默認構造函數。(或者能夠在基類中增長一個不帶參數的構造函數)這個問題將解決。 
代碼 b 採用的是調用基類帶參構造函數的方式:

代碼 b:

 1 class A  2 {  3     public:  4         A(int x, int y): i(x), j(y) {}  5     private:  6         int i, j;  7 };  8 
 9 class B : public A 10 { 11     public: 12         B() A(10,20) { cout << "init B" << endl; } 13 };

 

經過在基類中增長一個不帶參數的構造函數: 
代碼 c:

 1 class A  2 {  3     public:  4         A(int x, int y): i(x), j(y) {}  5         A();   //不帶參數的構造函數
 6     private:  7         int i, j;  8 };  9 
10 class B:public A 11 { 12     public: 13         B(): A(10,20) { cout << "init B" << endl; } 14 };

 

定義派生類賦值運算符

與拷貝和移動構造函數同樣,派生類的賦值運算符也必須爲其基類部分賦值。

1 // Base::operator=(const Base&) 不會被自動調用
2 D& D::operator=(const D &rhs) 3 { 4     Base::operator=(rhs);  //爲基類部分賦值 5     //按照過去的方式爲派生類的成員賦值
6     return *this; 7 }

 舉例說明:

 1 class base 
 2 {  3 public:  4   base(int initialvalue = 0): x(initialvalue) {}  5 
 6 private:  7   int x;  8 };  9 
10 class derived : public base 
11 { 12 public: 13   derived(int initialvalue): base(initialvalue), y(initialvalue) {} 14   derived& operator=(const derived& rhs); 15 
16 private: 17   int y; 18 }; 19 
20 邏輯上說,derived的賦值運算符應該象這樣: 21 derived& derived::operator = (const derived& rhs) // 錯誤的賦值運算符
22 {                                                 // 請注意d1的base部分沒有被賦值操做改變。
23   if (this == &rhs) 24     return *this; 25   y = rhs.y; 26   return *this; 27 } 28 
29 不幸的是,它是錯誤的,由於derived對象的base部分的數據成員x在賦值運算符中未受影響。例如,考慮下面的代碼段: 30 
31 void assignmenttester() 32 { 33   derived d1(0);      // d1.x = 0, d1.y = 0
34   derived d2(1);      // d2.x = 1, d2.y = 1
35 
36   d1 = d2;            // d1.x = 0, d1.y = 1
37 } 38 
39 
40 derived& derived::operator = (const derived& rhs) // 正確的賦值運算符
41 { 42   if (this == &rhs) 43     return *this; 44 
45   base::operator = (rhs);    // 調用this->base::operator=
46   y = rhs.y; 47 
48   return *this; 49 }
相關文章
相關標籤/搜索