C++ 拷貝構造函數和賦值運算符


  這篇文章主要介紹拷貝構造函數和賦值運算符的區別,以及在什么時候調用拷貝構造函數,什么情況下調用賦值運算符。    

  拷貝構造函數和賦值運算符

  在默認情況下(用戶沒有定義,但是也沒有顯示的刪除),編譯器會自動隱式生成一個拷貝構造函數和賦值運算符,但用戶可以使用delete來指定不生成拷貝構造函數和賦值運算符,這樣的對象就不能通過值傳遞,也不能進行賦值運算

 1 #include <iostream>
 2 
 3 using namespace std;  4 class Person {  5 public:  6  Person():{}  7     Person(const Person& p) = delete;  8     Person& operator= (const Person& p) = delete;  9 
10     void SetName( string strName ) 11  { 12         name = strName; 13  } 14     void SetAge(int nAge) 15  { 16         age = nAge; 17  } 18 private: 19     int age; 20     string name; 21 }; 22 int main() 23 { 24  Person p1; 25     p1.SetName("air"); 26     p1.SetAge(18); 27 
28     //Person p2(p1); 錯誤的
29     return 0; 30 }

上面定義的類Person顯式的刪除了拷貝構造函數和賦值運算符,在需要調用拷貝構造函數或者賦值運算符的地方,會提示無法調用該函數,它是已刪除的函數。

還有一點需要注意的是,拷貝構造函數必須以引用的方式傳遞參數,這是因為,在值傳遞給一個函數的時候,會調用拷貝構造函數生成函數的實參,如果拷貝構造函數的參數仍然是以值的方式,就會無限循環的調用下去,直到函數的棧溢出。

何時調用

  拷貝構造函數和賦值運算符的行為比較相似,都是將一個對象的值復制給另一個對象,但是其結果卻有些不同,拷貝構造函數使用傳入對象的值生成一個新的對象的實例,而賦值運算符是將對象的值復制給一個已經存在的實例。這種區別從兩者的名字也能輕易的分辨出來,拷貝構造函數也是一種構造函數,那么它的功能就是創建一個新的對象實例;賦值運算符是執行某種運算,將一個對象的值復制給另一個對象(已經存在的)。調用的是拷貝構造函數還是賦值運算符,主要是看是否有新的對象實例產生,如果產生了新的對象實例,那調用的就是拷貝構造函數;如果沒有,那就是對已有的對象賦值,調用的是賦值運算符。

調用拷貝構造函數主要有以下場景:

  1:對象作為函數的參數,以值傳遞的方式傳給函數。

  2:對象作為函數的返回值,以值的方式從函數返回。

  3:使用一個對象給另一個對象初始化。

代碼如下:

 1 #include <iostream>
 2 
 3 using namespace std;  4 class Person  5 {  6 public:  7  Person() {}  8     Person( const Person& p )  9  { 10         cout << "Copy Constructor" << endl; 11  } 12 
13     Person& operator=( const Person& p ) 14  { 15         cout << "Assign" << endl; 16         return *this; 17  } 18 
19 private: 20     int age; 21     string name; 22 }; 23 
24 void f( Person p ) 25 { 26     return; 27 } 28 
29 Person f1( ) 30 { 31  Person p; 32     return p; 33 } 34 
35 
36 int main() 37 { 38  Person p; 39     Person p1 = p;    // 1 
40     Person p2;  // 41     p2 = p;           // 2
42     f(p2);            // 3
43 
44     p2 = f1();        // 4
45 
46     Person p3 = f1(); // 5
47 
48     return 0; 49 }

 

1:雖然使用了“=”,但是實際上使用對象p來創建了一個新的對象p1.也就是產生了新的對象,所以調用的是拷貝構造函數。

2:首先聲明了一個對象p2,然后使用復制運算符"=",將p的值賦值給p2,顯然是調用了賦值運算符,為一個已經存在的對象賦值。

3:以值傳遞的方式將對象p2傳入函數f內,調用拷貝構造函數構建一個函數f可用的實參

4:這條語句拷貝構造函數和賦值運算符都調用了。函數f1以值的方式返回一個Person對象,在返回時會調用拷貝構造函數創建一個臨時對象tmp作為返回值;返回后調用賦值運算符將臨時對象tmp賦值給p2.

5:應該是首先調用拷貝構造函數創建臨時對象;然后再調用拷貝構造函數使用剛才創建的臨時對象創建新的對象p3,也就是會調用兩次拷貝構造函數。不過,編譯器也沒有那么傻,應該是直接調用拷貝構造函數使用返回值創建了對象p3。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM