加入有父類是這樣定義的: ios
class CA { public: CA() { cout << "using ca's constractor/n"; } CA(int k) { cout << "using ca's 2nd constractor, k is " << k << endl; m = k; }; virtual ~CA() { cout << "using ca's disconstractor/n"; } void output() { cout << "the m is " << m << endl; } private: int m; };
注意A類裏面有一個私有成員m. 函數
假設有一個子類是這樣定義的: spa
class CB : public CA { public: CB(int k) { m = k; } };
顯然是錯誤的,B類不可以直接訪問A類的成員m code
這樣定義也是錯誤的: 對象
class CB : public CA { public: CB(int k) { __super::CA((int)k); } };
這樣其實是在CB(int k)中構造了一個CA類的臨時變量實例,函數執行完以後就沒有了。若是有: 繼承
CB b(2); 執行的結果是: using ca's constractor using ca's 2nd constractor, k is 2 using ca's disconstractor using ca's disconstractor
這說明,先默認的調用CA()構造了一個CB的實例,而後又聲明瞭一個CA (2)的實例。 編譯器
正確的方法是這樣的: io
class CB:public CA { public: CB(int k):CA(k) { ..... } };
這就是在子類中顯示調用父類的構造函數。 編譯
------------------------------------- class
構造方法用來初始化類的對象,與父類的其它成員不一樣,它不能被子類繼承(子類能夠繼承父類全部的成員變量和成員方法,但不繼承父類的構造方法)。所以,在建立子類對象時,爲了初始化從父類繼承來的數據成員,系統須要調用其父類的構造方法。
若是沒有顯式的構造函數,編譯器會給一個默認的構造函數,而且該默認的構造函數僅僅在沒有顯式地聲明構造函數狀況下建立。
構造原則以下:
1. 若是子類沒有定義構造方法,則調用父類的無參數的構造方法。
2. 若是子類定義了構造方法,不管是無參數仍是帶參數,在建立子類的對象的時候,首先執行父類無參數的構造方法,而後執行本身的構造方法。
3. 在建立子類對象時候,若是子類的構造函數沒有顯示調用父類的構造函數,則會調用父類的默認無參構造函數。
4. 在建立子類對象時候,若是子類的構造函數沒有顯示調用父類的構造函數且父類本身提供了無參構造函數,則會調用父類本身的無參構造函數。
5. 在建立子類對象時候,若是子類的構造函數沒有顯示調用父類的構造函數且父類只定義了本身的有參構造函數,則會出錯(若是父類只有有參數的構造方法,則子類必須顯示調用此帶參構造方法)。
6. 若是子類調用父類帶參數的構造方法,須要用初始化父類成員對象的方式,好比:
#include <iostream.h> class animal { public: animal(int height, int weight) { cout<<"animal construct"<<endl; } … }; class fish:public animal { public: fish():animal(400,300) { cout<<"fish construct"<<endl; } … }; void main() { fish fh; }
在fish類的構造函數後,加一個冒號(:),而後加上父類的帶參數的構造函數。這樣,在子類的構造函數被調用時,系統就會去調用父類的帶參數的構造函數去構造對象。這種初始化方式,還經常使用來對類中的常量(const)成員進行初始化,以下面的代碼所示:
class point { public: point():x(0),y(0) private: const int x; const int y; };
固然,類中普通的成員變量也能夠採起此種方式進行初始化,然而,這就沒有必要了。