【自我總結】
1.默認構造函數不僅可以是無參的,也可以是有參的,但所有參數必須指定默認值。一個類只能有一個默認構造函數。
2.什么時候調用默認構造函數?
a.聲明類的對象時沒有括號時。如:classA objA;
b.子類構造函數沒有顯式調用父類構造函數時
3.構造函數中的默認參數要從右向左指定。
classA(int a=0, int b){}; //錯誤
classA(int a, int b=0){}; //正確
構造方法用來初始化類的對象,與父類的其它成員不同,它不能被子類繼承(子類可以繼承父類所有的成員變量和成員方法,但不繼承父類的構造方法)。因此,在創建子類對象時,為了初始化從父類繼承來的數據成員,系統需要調用其父類的構造方法。
如果沒有顯式的構造函數,編譯器會給一個默認的構造函數,並且該默認的構造函數僅僅在沒有顯式地聲明構造函數情況下創建。
構造原則如下:
1. 如果子類沒有定義構造方法,則調用父類的無參數的構造方法。
2. 如果子類定義了構造方法,不論是無參數還是帶參數,在創建子類的對象的時候,首先執行父類無參數的構造方法,然后執行自己的構造方法。
3. 在創建子類對象時候,如果子類的構造函數沒有顯示調用父類的構造函數,則會調用父類的默認無參構造函數。
4. 在創建子類對象時候,如果子類的構造函數沒有顯示調用父類的構造函數且父類自己提供了無參構造函數,則會調用父類自己的無參構造函數。
5. 在創建子類對象時候,如果子類的構造函數沒有顯示調用父類的構造函數且父類只定義了自己的有參構造函數,則會出錯(如果父類只有有參數的構造方法,則子類必須顯示調用此帶參構造方法)。
6. 如果子類調用父類帶參數的構造方法,需要用初始化列表的方式。
結論:子類構造函數必須要調用父類的構造函數(無論顯式還是隱式),本質原因在於繼承的性質決定了必須先有父再有子!
1. 默認構造函數主要是用來完成如下形式的初始化的:
testClass classA; // 或者 testClass *classA = new testClass;
在這種情況下,如果沒有提供默認構造函數,編譯器會報錯;
非默認構造函數在調用時接受參數,如以下形式:
testClass classA(12,'H'); //或者 testClass *classA = new testClass(12,'H');
2. 如果程序猿沒有定義任何構造函數,則編譯器會自動定義默認構造函數,其形式如 testClass() {}; 可以看出,編譯器自動提供的默認構造函數是 啥也沒有啊 ;
3. 定義默認構造函數有兩種方式,如上述代碼展示的,一是定義一個無參的構造函數,二是定義所有參數都有默認值的構造函數 ;
4. 注意:一個類只能有一個默認構造函數!也就是說上述兩種方式不能同時出現,一般選擇 testClass(); 這種形式的默認構造函數 ;
5. 只要程序猿定義了構造函數,編譯器就不會再提供默認構造函數了,所以,程序猿最好再手動定義一個默認構造函數,以防出現 testClass a; 這樣的錯誤。
#include <iostream> #include <string.h> using namespace std; class A { public: A(int x):a(x){}; void printA (void) { cout << "a = " << a << endl; } private: int a; }; class B: public A { public: B(int x=0, int y=0):A(x) { b = y; } void printB(void) { cout << "b = " << b << endl; } private: int b; }; int main() { B obj(1,2); obj.printA(); obj.printB(); return 0; }