4

我一直在搞包裝在容器類中的引用。爲什麼下面的代碼合法,看起來行爲正確?C++引用可以賦值嗎?

#include <iostream> 

class Foo 
{ 
public: 
    Foo(int i) : i_(i) {} 
    int i_; 
}; 

class FooWrapper 
{ 
public: 
    FooWrapper(Foo& foo) : foo_(foo) {} 
    Foo& foo_; 
}; 

int main(int argc, char* argv[]) 
{ 
    Foo foo(42); 
    FooWrapper fw(foo); 
    FooWrapper fw2 = fw; 
    std::cout << fw2.foo_.i_ << std::endl; 
    return 0; 
} 

在沒有明確的operator=的,我相信C++做一個成員複製。所以當我做FooWrapper fw2 = fw;,這不是兩個操作:(1)創建FooWrapper fw與默認ctor後跟(2)分配從fwfw2?我相信這不會發生,因爲不能創建未初始化的引用,所以實際上將fw2的創建視爲複製構造?

我有時不清楚副本構建與分配的角色;他們似乎有時會流血,就像在這個例子中一樣,但可能有一些我不知道的規則。我會很感激一個解釋。

回答

3

在下面的線,你正在構建fw2通過使其成爲fw的副本。也就是說,您正在調用複製構造函數。

FooWrapper fw2 = fw; 

下面是對如何default constructorcopy constructorcopy assignment operator,和move assignment operator(從C++ 11)被調用的(online)的例子。

#include <iostream> 

struct foo 
{ 
    foo() {std::cout << "Default constructor" << '\n';} 
    foo(foo const&) {std::cout << "Copy constructor" << '\n';} 
    foo& operator=(foo const&) {std::cout << "Copy assignment operator" << '\n'; return *this; } 
    foo& operator=(foo &&) {std::cout << "Move assignment operator" << '\n'; return *this; } 
}; 

int main(int argc, char* argv[]) 
{ 
    foo a;   // Default constructor 
    foo b = a;  // Copy constructor 
    foo c;   // Default constructor 
    c = b;   // Copy assignment operator 
    b = std::move(c); // Move assignment operator 
} 
4

儘管=的語法,FooWrapper fw2 = fw;複製構造fw2(使用複製構造函數)。根本不涉及默認構造和分配。

並回答標題中的問題:否,不能分配參考。如果你寫的代碼,試圖實際上默認構造或分配FooWrapper,如:

FooWrapper fw2; 
fw2 = fw; 

...這會失敗。正式的,只需要一個「診斷」。非正式地說,我所知道的每個編譯器都會拒絕編譯它。

3

該初始化實際上調用了複製構造函數。 FooWrapper fw2 = fw; ,相當於 FooWrapper fw2(fw);

隱含定義拷貝構造函數並不需要創建一個未初始化的參考

參考: http://en.cppreference.com/w/cpp/language/copy_constructor

+0

是的,這就是我的意思。改變了措辭'隱含定義拷貝constructor' –

+0

措詞還涉及到這樣的事實,時下一個可以顯式地請求編譯器通過'default'關鍵字生成一個複製構造: 'CLASS_NAME(常量CLASS_NAME&)=默認值;' –