這裏先給出結論,在貼出代碼與執行結果~函數
一個派生類構造函數的執行順序以下:測試
第一步執行:虛擬基類的構造函數(多個虛擬基類則按照繼承的順序執行構造函數)。spa
第二步執行:基類的構造函數(多個普通基類也按照繼承的順序執行構造函數)。code
第三步執行:類類型的成員對象的構造函數(按照初始化順序)。對象
第四部執行:派生類本身的構造函數。繼承
若是一個派生類不只繼承於一個基類,並且還有這個基類的成員對象,那麼會進行兩次構造函數的執行(一個用於初始化派生類中基類部分的內部成員,另外一個是初始化派生類的基類類型成員變量的內部成員),詳細看派生類Son2的執行結果。內存
你字符串
下面聲明瞭A,B,C,D,Object1,Object2留個基類以及Son1,Son2,Son3,Son4,Son5(Son5是一個錯誤的例子,編譯不能經過)cmd
每一個基類都有兩個構造函數,默認的構造函數不接受參數,輸出的Default+字符串io
帶參數的輸出的本身類的特有信息。
(爲了方便觀看,我在後面會再貼一下結論)
參考Son1:能夠驗證上述派生類構造函數的執行順序;
參考Son2:能夠驗證構造函數是嚴格照上面所說的順序執行,與初始化的順序無關。同時,若是不顯示的執行基類構造函數的初始化,就會按照順序調用默認的構造函數。
參考Son3:能夠說明繼承下執行的構造函數與類類型的成員變量的構造函數是佔用兩個不一樣的內存地址空間,兩者不會相互影響。
參考Son4:能夠說明,不管是否顯示的初始化類類型的成員變量,都會按照成員變量在類中的聲明順序執行構造函數。
參考Son5:這個解決了我以前的疑問,若是在派生類的構造函數中初始化類類型的成員對象會怎麼樣,發現這樣是不可取的,由於在類的聲明中是不能夠實際分配內存的,可是能夠聲明。
(關於Son5的理解須要進一步闡明:這裏可能涉及到了C++內存分配,拷貝賦值的原理,若是不是很懂的話這裏咱們暫且按我說的方式去理解。)
classA { public: A(intnum){Show();} A(){cout<<"Defaultaaa"<<endl;} voidShow(){cout<<"aaa"<<endl;} }; classB { public: B(intnum){Show();} B(){cout<<"Defaultbbb"<<endl;} voidShow(){cout<<"bbb"<<endl;} }; classC { public: C(intnum){Show();} C(){cout<<"Defaultccc"<<endl;} voidShow(){cout<<"ccc"<<endl;} }; classD { public: D(intnum){Show();} D(){cout<<"Defaultddd"<<endl;} voidShow(){cout<<"ddd"<<endl;} }; classObject1 { public: Object1(intnum){Show();} Object1(){cout<<"DefaultObject1"<<endl;} voidShow(){cout<<"Object1"<<endl;} }; classObject2 { public: Object2(intnum){Show();} Object2(){cout<<"DefaultObject2"<<endl;} voidShow(){cout<<"Object2"<<endl;} }; classSon1:publicA,virtualpublicB,publicC,virtualpublicD { public: Son1():A(1),B(1),C(1),D(1),ob1(1),ob2(1){ cout<<"son1"<<endl; } Object1ob1; Object2ob2; }; classSon2:publicA,virtualpublicB,publicC,virtualpublicD { public: Son2():C(1),A(1),ob1(1),ob2(1){ //結果仍然是先執行A的構造函數,其次是C的,證實與初始 cout<<"son2"<<endl; //化的順序無關 } Object1ob1; Object2ob2; }; classSon3:publicA,virtualpublicB,publicC,virtualpublicD,virtualpublicObject1,publicObject2 { public: Son3():ob1(1),ob2(1){ cout<<"son3"<<endl; } Object1ob1; Object2ob2; }; classSon4:publicA,virtualpublicB,publicC,virtualpublicD,virtualpublicObject1,publicObject2 { public: Son4():ob2(1){ //注意,若是Object1沒有默認構造函數,這裏將沒法編譯經過 cout<<"son4"<<endl; } Object1ob1; Object2ob2; }; //class Son5:publicA,virtual public B,publicC,virtual public D //{ //public: // Son5():A(1),B(1),C(1),D(1){ // cout<<"son5"<<endl; // ob2=ob1; //這裏編譯不經過,沒有與這些操做數匹配的」=」運算符(兩者類型不一樣,須要從新定義‘=’) // ob1(1); // ob2(2); //這裏編譯不經過,在沒有適當的operate()的狀況下調用類類型對象 // } // Object1 ob1(1); // 這裏編譯不經過,由於類的成員聲明不須要分配內存,這樣寫就至關於執行 //構造函數並分配內存了 // Object2 ob2; //}; int_tmain(intargc, _TCHAR* argv[]) { cout<<"------------SON1------------"<<endl; Son1son1; cout<<"------------SON2------------"<<endl; Son2son2; cout<<"------------SON3------------"<<endl; Son3son3; cout<<"------------SON4------------"<<endl; Son4 son4; Object1obj; //son4.ob1(1); //這句話是錯誤的編譯不經過,在沒有適當的operate()的狀況下調用類類型對象 son4.ob1=obj; system("pause"); //這句只是爲了讓cmd停留顯示,以避免閃退(VS控制檯程序須要) return 0; }
以上代碼是在VS2012ConsoleApplication控制檯下編譯測試的,結果以下:
再貼一遍:
參考Son1:能夠驗證一開始介紹的派生類構造函數的執行順序;
參考Son2:能夠驗證構造函數是嚴格照上面所說的順序執行,與初始化的順序無關(儘管表面上C比A初始化的要早)。同時,若是不顯示的執行基類構造函數的初始化,就會按照順序調用默認的構造函數。
參考Son3:能夠說明繼承下執行的構造函數與類類型的成員變量的構造函數是佔用兩個不一樣的內存地址空間,兩者不會相互影響。
參考Son4:能夠說明,不管是否顯示的初始化類類型的成員變量,都會按照成員變量在類中的聲明順序執行構造函數。
參考Son5:這個解決了我以前的疑問,若是在派生類的構造函數中初始化類類型的成員對象會怎麼樣,發現這樣是不可取的,由於在類的聲明中是不能夠實際分配內存的,可是能夠聲明。