2013-02-12 81 views
2

這是一個非常基本的問題,但我對此感到困惑。說我創建了一個對象複製構造對象的C++引用

MyObject a

它配備了一個拷貝構造函數,所以我知道我能做到這一點:

MyObject b(a); 但我能做到這一點?

MyObject& b(a);

如果我這樣做:

MyObject b = a;什麼是b?道歉,如果這個問題太重要,不能打擾張貼。

回答

7

MyObject& b(a)與複製構造函數沒有任何關係。它只是創建b這是對象a的引用。沒有被複制。將b想象爲對象a的別名。您可以等效地使用ba來引用同一個對象。

MyObject b = a;將使用複製構造函數,就像MyObject b(a);會。


有兩種形式的初始化的:T x = a;稱爲複製初始化; T x(a)T x{a}被稱爲直接初始化

T是引用類型時,使用哪種類型的初始化並不重要。兩者具有相同的效果。

T是類類型,我們有兩種可能性:

  1. 如果初始化是直接初始化MyClass b(a);),或者,如果是副本初始化與所衍生aTMyClass b = a;)相同或相同的類型:選擇T的適用構造函數來構造該對象。

    正如您所看到的,您的兩個示例均屬於此類類別初始化程序的類別。

  2. 如果初始化是任何其他形式的複製初始化,任何用戶定義的轉換序列將被視爲後跟直接初始化。用戶定義的轉換序列基本上是任何標準轉換序列,其中包含一個轉換構造函數。

    c如果是Foo類型的並有從Foo轉換構造函數MyClass,然後MyClass b = c;將相當於MyClass b(MyClass(c));

所以基本上,如果源和目標類型相同,兩種形式的初始化都是等效的。如果需要轉換,它們不是。一個簡單的例子來說明這就是:

#include <iostream> 

struct Bar { }; 

struct Foo 
{ 
    Foo(const Foo& f) { std::cout << "Copy" << std::endl; } 
    Foo(const Bar& b) { std::cout << "Convert" << std::endl; } 
}; 

int main(int argc, const char* argv[]) 
{ 
    Bar b; 
    Foo f1(b); 
    std::cout << "----" << std::endl; 
    Foo f2 = b; 
    return 0; 
} 

這個程序的輸出(禁用複製省略)是:

Convert 
---- 
Convert 
Copy 

當然,還有很多其他類型的initialisations的太(名單初始化,字符數組,聚合等)。

+0

晶瑩剔透的解釋。謝謝! – user1861088 2013-02-12 21:38:50

+0

只是確定我明白了,所以'MyObject&b = a'與'MyObject&b(a)'和'MyObject b(a)'到'MyOjbect b = a'絕對等價? – user1861088 2013-02-12 21:40:37

+0

@ user1861088不是真的,搜索複製初始化與直接初始化。 – 2013-02-12 21:43:08

0

這是我的觀點:

引用是依賴於某人的其他的存儲,每當ü訪問的參考,你所訪問的存儲。由於它們只是一個別名,因此不能將引用分配給null。創建時必須初始化引用。 (指針可以在任何時候被初始化。)

所以當你說

MyObject& b(a); 

編譯器分配一塊存儲器B的,併爲結參照。

當你說

MyObject b = a; 

你傳遞的對拷貝構造函數的引用,並從它創建新型B。請注意,只有在爲其編寫了拷貝構造函數的情況下才能進行深層拷貝。否則它會調用默認的複製構造函數,從而導致淺拷貝。

,當你說

a = b; // after creating these objects 

它翻譯爲對象::運算符=(const對象&),從而A.operator =(B)被調用(調用簡單的複製,而不是拷貝構造函數!)

+0

當你說'MyObject&b(a)'時,編譯器不會分配一塊存儲'a'並將引用連接到那塊存儲。它分配一個名爲'b'的引用並將其綁定到'a'。並且它不能準確地說複製構造函數會導致深層複製。它可能 - 但它不是必需的。 – 2013-02-12 22:13:46

+0

@尼克:我編輯了我的答案。對於深拷貝的好處,我假定他有一個有效的拷貝構造函數。 – DotNetUser 2013-02-12 22:24:15