c++類物件初始化方式總結
阿新 • • 發佈:2019-01-23
在《inside the c++ object model》一書中談到copy constructor的構造操作,有三種情況下,會以一個object的內容作為另一個object的初值:
第一種情況: XX aa = a;
第二種情況: XX aa(a);
第三種情況: extern fun(XX aa); fun(a)函式呼叫
第四種情況: XX fun(){...}; XX a = fun();函式返回值的時候
下面我們就上述的四種情況來一一驗證:
測試結果:class ClassTest{ public: ClassTest()//定義預設建構函式 { c[0] = '\0'; cout << "ClassTest()" << endl; } ClassTest& operator=(const ClassTest &ct) //過載賦值操作符 { strcpy_s(c, ct.c); cout << "ClassTest& operator=(const ClassTest &ct)" << endl; return *this; } ClassTest(const char *pc) { strcpy_s(c, pc); cout << "ClassTest (const char *pc)" << endl; } ClassTest(const ClassTest& ct)//複製建構函式 { strcpy_s(c, ct.c); cout << "ClassTest(const ClassTest& ct)" << endl; } private: char c[256]; }; ClassTest func(ClassTest temp){ return temp; } int main(){ cout << "ct1: "; ClassTest ct1("ab");//直接初始化 cout << "ct2: "; ClassTest ct2 = "ab";//複製初始化 /*輸出說明: ClassTest ct2 = "ab"; 它本來是要這樣來構造物件的:首先呼叫建構函式ClassTest(const char *pc)函式建立一個臨時物件, 然後呼叫複製建構函式,把這個臨時物件作為引數,構造物件ct2。然而編譯也發現,複製建構函式是 公有的,即你明確地告訴了編譯器,你允許物件之間的複製,而且此時它發現可以通過直接呼叫過載的 建構函式ClassTest(const char *pc)來直接初始化物件,而達到相同的效果,所以就把這條語句優化為 ClassTest ct2("ab")。 */ cout << "ct3: "; ClassTest ct3 = ct1;//複製初始化 cout << "ct4: "; ClassTest ct4(ct1);//直接初始化 cout << "ct5: "; ClassTest ct5 = ClassTest();//複製初始化 cout << "ct6: "; ClassTest ct6;//複製初始化 ct6 = "caoyan is a good boy!"; cout << "ct7: "; ClassTest ct7; ct7 = func(ct6); return 0; }
我們可以看到,比較複雜的是ct6和ct7,其中ct6還是比較好理解的,ct7這種情況比較難懂,為什麼會有兩個拷貝建構函式的呼叫????
第一次拷貝建構函式的呼叫:第一次很簡單,是因為函式引數的傳遞,將ct6作為引數傳遞給temp,用ct6的值初始化temp會呼叫拷貝建構函式;
第二次拷貝建構函式的呼叫:因為要返回一個ClassTest物件,我們的編譯器怎麼做????首先它將temp物件拷貝到func函式的上一級棧幀中,它的上一級棧幀是main函式的棧幀,那麼當函式返回時,引數出棧,temp物件的記憶體空間就會被收回,但是它的值已經被拷貝到main棧幀的一個預留空間中,所以從temp到預留空間的拷貝也是呼叫拷貝建構函式,最後一步就是給ct7賦值,毫無疑問呼叫賦值建構函式;對棧幀不同的同學可以看看《程式設計師的自我修養》一書,裡面講得很詳細!!!!