今天同事問了一個關于拷貝建構式的問題,類中包含指標的情況,今天就來說說c++的拷貝建構式,
c++的拷貝建構式是建構式的一種,是對類物件的初始化,拷貝建構式只有一個引數就是本類的參考,
注意,默認建構式(即無參建構式)不一定存在,但是拷貝建構式總是會存在,
下面是一個拷貝建構式的例子,
1 #include<iostream> 2 using namespace std; 3 class A{ 4 public: 5 int a; 6 A(int value){ 7 a = value; 8 } 9 void show(){ 10 cout<<a<<endl; 11 } 12 }; 13 int main(){ 14 A test_a(10); 15 test_a.show(); 16 17 A test_b(test_a); 18 test_b.show(); 19 20 return 0; 21 }
輸出結果為:
10 10
如果撰寫了拷貝建構式,則默認拷貝建構式就不存在了,下面是一個非默認拷貝建構式的例子,
1 #include<iostream> 2 using namespace std; 3 class A{ 4 public: 5 int a; 6 A(int value){ 7 a = value; 8 } 9 A(A& tmp){ 10 a = tmp.a; 11 cout<<"call copy construct"<<endl; 12 } 13 void show(){ 14 cout<<a<<endl; 15 } 16 }; 17 int main(){ 18 A test_a(10); 19 test_a.show(); 20 21 A test_b(test_a); 22 test_b.show(); 23 24 return 0; 25 }
輸出結果為:
10 call copy construct 10
拷貝建構式被呼叫的三種情況
拷貝建構式在以下三種情況下會被呼叫,
1) 當用一個物件去初始化同類的另一個物件時,會引發拷貝建構式被呼叫,例如,下面的兩條陳述句都會引發拷貝建構式的呼叫,用以初始化 test_b,
1 A test_b(test_a); 2 A test_b = test_a;
這兩條陳述句是等價的,
注意,第二條陳述句是初始化陳述句,不是賦值陳述句,賦值陳述句的等號左邊是一個早已有定義的變數,賦值陳述句不會引發拷貝建構式的呼叫,例如:
1 A test_a,test_b; 2 test_b = test_a;
這條陳述句不會引發拷貝建構式的呼叫,因為 test_b 早已生成,已經初始化過了,
2) 如果函式 F 的引數是類 A 的物件,那么當 F 被呼叫時,類 A 的拷貝建構式將被呼叫,換句話說,作為形參的物件,是用復制建構式初始化的,而且呼叫拷貝建構式時的引數,就是呼叫函式時所給的實參,
3) 如果函式的返冋值是類 A 的物件,則函式返冋時,類 A 的拷貝建構式被呼叫,換言之,作為函式回傳值的物件是用拷貝建構式初始化 的,而呼叫拷貝建構式時的實參,就是 return 陳述句所回傳的物件,例如下面的程式:
1 #include<iostream> 2 using namespace std; 3 class A{ 4 public: 5 int a; 6 A(int value){ 7 a = value; 8 } 9 A(A& tmp){ 10 a = tmp.a; 11 cout<<"call copy construct"<<endl; 12 } 13 void show(){ 14 cout<<a<<endl; 15 } 16 }; 17 A Func() { 18 A test_a(4); 19 return test_a; 20 } 21 int main(){ 22 Func().show(); 23 24 return 0; 25 }
輸出結果:
call copy construct 4
針對于第三條,有些編譯器可能會有以下的結果:
4
這是因為編譯器編譯的時候進行了優化,函式回傳值物件就不用拷貝建構式初始化了,這其實并不符合 C++的標準,
淺拷貝和深拷貝
重頭戲來了,內含指標的拷貝建構式,C++是如何實作的呢,來看個例子:
1 #include<iostream> 2 using namespace std; 3 class A{ 4 public: 5 int a; 6 int *p; 7 A(int value1, int value2){ 8 a = value1; 9 p = new int(value2); 10 } 11 ~A(){ 12 delete p; 13 } 14 15 void show(){ 16 cout<<a<<endl; 17 cout<<p<<endl; 18 cout<<*p<<endl; 19 } 20 }; 21 22 int main(){ 23 A test_a(10,20); 24 test_a.show(); 25 26 A test_b(test_a); 27 test_b.show(); 28 29 return 0; 30 }
輸出結果如下:
10 0xf19010 20 10 0xf19010 20 *** glibc detected *** ./a.out: double free or corruption (fasttop): 0x0000000000f19010 *** ...
可以看到對于class A 的物件 test_a 和 test_b 指標p 指向了同一塊記憶體,在物件析構的時候被析構了兩次導致了crash,這就是我們常說的淺拷貝,
因此,在我們日常撰寫代碼的時候特別需要注意這一點,對于指標我們需要相應的開辟一塊新的記憶體,將指向的值拷貝過來,也就是所謂的深拷貝,下面是正確的寫法:
1 #include<iostream> 2 using namespace std; 3 class A{ 4 public: 5 int a; 6 int *p; 7 A(int value1, int value2){ 8 a = value; 9 p = new int(value2); 10 } 11 A(A& tmp){ 12 a = tmp.a; 13 p = new int(* tmp.p); 14 } 15 ~A(){ 16 delete p; 17 } 18 19 void show(){ 20 cout<<a<<endl; 21 cout<<p<<endl; 22 cout<<*p<<endl; 23 } 24 }; 25 26 int main(){ 27 A test_a(10,20); 28 test_a.show(); 29 30 A test_b(test_a); 31 test_b.show(); 32 33 return 0; 34 }
輸出結果如下:
10 0xd4d010 20 10 0xd4d030 20
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/93387.html
標籤:C++
上一篇:實驗作業
下一篇:測驗博客
