2015-01-06 13 views
5

我遇到了一個測驗,它說下面第18行中的代碼是不合格的,因爲「當需要複製的成員之一是參考時,使用隱式定義的賦值運算符是不合適的。」爲什麼如果一個類的成員是一個引用,複製一個對象是非法的?

我無法理解。爲什麼參考不能被複制?爲什麼16行是合法的?第16行與第18行很相似,複製構造函數仍然需要複製,對吧?

1 #include <iostream> 
2 
3 struct A 
4 { 
5 A(int& var) : r(var) {} 
6 
7 int &r; 
8 }; 
9 
10 int main(int argc, char** argv) 
11 { 
12 int x = 23; 
13 
14 A a1(x); 
15 
16 A a2 = a1; 
17 
18 a2 = a1; 
19 
20 return 0; 
21 } 
+2

[你打算髮布整個測驗?](http://stackoverflow.com/questions/27792560/c-why-constructor-aa-a-is-illegal) – WhozCraig

+0

啊..這是有道理的。 grats 97.4%測試順便說一句。 – WhozCraig

+1

非法*分配*,而不是*複製*。 – Potatoswatter

回答

1

因爲C++是非法的,所以要重新分配參考。

int &a = some_int; 
a = some_other_int; // value copied not reference 
a = some_int; // value copied not reference 

當您使用分配運算符(由編譯器生成),它一味做對象的副本,從而試圖重新分配給您的參考,因此是無效的。

當您說a2 = a1;時,編譯器會嘗試重新指派a1.ra2.r,使其在編譯時失敗,因爲它不合格。

您可以將參考視爲automatically dereferenced constant pointer。所以行a2 = a1;將保持格式不正確,原因與下面的類相同。

struct A 
{ 
    A(int *var) : p(var) {} 
    int * const p; 
}; 
+3

重新引用參考文件是非法的。甚至沒有它的語法。然而,你稱爲非法的聲明不是。 –

+0

您放棄了錯誤的評論,但是您的推理仍然不正確,因爲'a1.r = a2.r'不會不合格。從另一個引用的初始化也不會是不合格的,因爲它只會將第二個引用綁定到第一個引用的引用。 –

+0

引用就像一個永久解除引用的指針。 – seand

6

第16行使用複製構造函數,第18行使用賦值運算符operator=。兩種不同的功能有不同的限制。

因爲引用不能被反彈,所以編譯器不能生成有意義的隱式賦值運算符。因此它拒絕這樣做,併產生一個錯誤。

複製構造函數第一次生成對象,因此它可以按照您在自己的構造函數中的相同方式綁定該引用。

3

帶引用成員的類沒有默認提供的複製/移動賦值運算符。建立綁定後,引用不能被引用到另一個變量。簡而言之,複製構造函數正在進行初始建立,而默認賦值運算符將嘗試更改它綁定後。

因此,標準將這種情況稱爲默認複製和移動賦值操作符。

C++ 11§12.8p23

類X A拖欠複製/移動賦值運算符被定義爲已刪除如果X具有:

  • 用的變體構件非平凡對應賦值運算符,X是類聯合類,或者是非常量非類類型(或其數組)的非靜態數據成員或
  • 參考類型的非靜態數據成員
  • 類型爲M(或其數組)的非靜態數據成員,由於重載解析而無法複製/移動(13。3)適用於M的相應賦值運算符,會導致從默認賦值運算符或直接或虛擬基類B中刪除或無法訪問的含糊不清或功能,這些直接或虛擬基類B由於過載分辨率而無法複製/移動適用於B的相應賦值運算符,會導致從默認賦值運算符中刪除或無法訪問的歧義或函數,或移動賦值運算符,非靜態數據成員或直接基類與一個沒有移動賦值運算符並且不是可微複製的類型,或者任何直接或間接的虛擬基類。

您當然可以自己編寫過載。

#include <iostream> 

struct A 
{ 
    A(int& var) : r(var) {} 

    int &r; 

    A& operator=(const A& obj) 
    { 
     r = obj.r; // value copied, reference-binding remains the same 
     return *this; 
    } 
}; 

int main(int argc, char** argv) 
{ 

    int x = 42; 
    int y = 43; 

    A a1(x); 
    A a2(y); 

    A a3 = a1; // legal. default copy-ctor invoked 
    a3 = a2; // legal. user-defined copy-assignment invoked 

    std::cout << x << ',' << y << '\n'; 

    return 0; 
} 

輸出

43,43 

但這不會(且不能)重新綁定參考。此處提供的過載將更改參考的數據;而不是引用本身。這種區分很重要。

希望這會有所幫助。

相關問題