test1:

1 #include<iostream> 2 using namespace std; 3 class Copy_construction { 4 public: 5 Copy_construction(int a = 0) 6 { 7 this->a = a; 8 cout << "這是有默認參數的構造函數!\n"; 9 } 10 Copy_construction(const Copy_construction &obj) 11 { 12 cout << "這是拷貝構造函數!\n"; 13 a = obj.a; 14 } 15 ~Copy_construction() 16 { 17 cout << "一個對象被析構了!\n"; 18 } 19 private: 20 int a; 21 }; 22 void fuc(Copy_construction t) 23 { 24 cout << "fuc函數!\n"; 25 } 26 void play_empty(void) 27 { 28 Copy_construction t1;//調用有默認實參的構造函數 29 Copy_construction t2 = t1;//調用拷貝構造函數 30 Copy_construction t3(t2);//調用拷貝構造函數 31 cout << "_________________\n"; 32 fuc(t3);//實參初始化形參,調用拷貝構造函數 33 } 34 int main() 35 { 36 play_empty(); 37 38 cout << "hello world!\n"; 39 return 0; 40 }
運行結果
test2:
修改fuc函數為引用或者指針類型。
1 void fuc(Copy_construction *t) 2 { 3 cout << "fuc函數!\n"; 4 } 5 6 7 void fuc(Copy_construction &t) 8 { 9 cout << "fuc函數!\n"; 10 } 11 12 /*****引用或者指針類型調用時不會調用拷貝構造函數****/
test3:
匿名對象的出現:
1 #include<iostream> 2 using namespace std; 3 class Copy_construction { 4 public: 5 Copy_construction(int a = 0) 6 { 7 this->a = a; 8 cout << "這是有默認參數的構造函數!\n"; 9 } 10 Copy_construction(const Copy_construction &obj) 11 { 12 cout << "這是拷貝構造函數!\n"; 13 a = obj.a; 14 } 15 ~Copy_construction() 16 { 17 cout << "一個對象被析構了!\n"; 18 } 19 private: 20 int a; 21 }; 22 Copy_construction fuc(void) 23 { 24 cout << "fuc函數!\n"; 25 Copy_construction A; 26 return A;//調用拷貝構造函數,生成匿名對象 27 }//運行到該處,先析構對象A,匿名對象是否析構要看怎么去接 28 //如下所示直接調用fuc()則此時匿名對象會被立即析構 29 void play_empty(void) 30 { 31 fuc(); 32 } 33 int main() 34 { 35 play_empty(); 36 37 cout << "hello world!\n"; 38 return 0; 39 }
如果直接顯示調用構造函數,要看怎么去接這個函數, Copy_construction(1);調用之后馬上執行析構匿名對象, Copy_construction T= Copy_construction(1);不會馬上析構還會轉正。
test4:
修改fuc函數的返回類型為引用或者指針:
1 Copy_construction *fuc(void) 2 { 3 cout << "fuc函數!\n"; 4 Copy_construction A; 5 return &A; 6 } 7 8 Copy_construction &fuc(void) 9 { 10 cout << "fuc函數!\n"; 11 Copy_construction A; 12 return A; 13 } 14 15 16 /********返回類型為指針或者引用不會調用拷貝構造函數*********/
test5:
改變接匿名對象的方式:
1 #include<iostream> 2 using namespace std; 3 class Copy_construction { 4 public: 5 Copy_construction(int a = 0) 6 { 7 this->a = a; 8 cout << "這是有默認參數的構造函數!\n"; 9 } 10 Copy_construction(const Copy_construction &obj) 11 { 12 cout << "這是拷貝構造函數!\n"; 13 a = obj.a; 14 } 15 ~Copy_construction() 16 { 17 cout << "一個對象被析構了!\n"; 18 } 19 private: 20 int a; 21 }; 22 Copy_construction fuc(void) 23 { 24 cout << "fuc函數!\n"; 25 Copy_construction A; 26 return A;//調用拷貝構造函數,產生匿名對象 27 }//析構對象A,根據下面代碼的接匿名對象的方式, 28 //此時匿名對象不僅不會馬上析構,還會轉正成為對象B 29 //從c++設計哲學上來說,這也是提高效率的一種方式,這樣的設計是合理的,因為你想創建對象B,我就不用再新開辟內存了,直接用之前的匿名對象代替 30 void play_empty(void) 31 { 32 Copy_construction B=fuc();//這里不會調用拷貝構造函數,匿名對象直接轉正了 33 cout << "匿名對象轉正!\n"; 34 } 35 int main() 36 { 37 play_empty(); 38 39 cout << "hello world!\n"; 40 return 0; 41 }
test6:
再改變接匿名對象的方式,重寫play_empty()函數:
void play_empty(void) { Copy_construction B; B= fuc(); cout << "匿名對象不會轉正!\n"; } //如上所示代碼,此時對象B會開辟內存,在用返回的匿名對象賦值給B,將會在賦值完成之后立即析構匿名對象,這個時候匿名對象不會轉正。
summary:以下情況會調用拷貝構造函數
1.直接初始化和拷貝初始化時
2.將一個對象作為實參傳遞給一個非引用或非指針類型的形參時
3.從一個返回類型為非引用或非指針的函數返回一個對象時
4.用花括號列表初始化一個數組的元素或者一個聚合類(很少使用)中的成員時。