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

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

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

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

 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顯式的刪除了拷貝構造函數和賦值運算符,在須要調用拷貝構造函數或者賦值運算符的地方,會提示沒法調用該函數,它是已刪除的函數。spa

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

什麼時候調用code

  拷貝構造函數和賦值運算符的行爲比較類似,都是將一個對象的值複製給另外一個對象,可是其結果卻有些不一樣,拷貝構造函數使用傳入對象的值生成一個新的對象的實例,而賦值運算符是將對象的值複製給一個已經存在的實例。這種區別從二者的名字也能輕易的分辨出來,拷貝構造函數也是一種構造函數,那麼它的功能就是建立一個新的對象實例;賦值運算符是執行某種運算,將一個對象的值複製給另外一個對象(已經存在的)。調用的是拷貝構造函數仍是賦值運算符,主要是看是否有新的對象實例產生,若是產生了新的對象實例,那調用的就是拷貝構造函數;若是沒有,那就是對已有的對象賦值,調用的是賦值運算符。對象

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

  1:對象做爲函數的參數,以值傳遞的方式傳給函數。編譯器

  2:對象做爲函數的返回值,以值的方式從函數返回。string

  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。

相關文章
相關標籤/搜索