2012-11-26 175 views
0

爲什麼這段代碼無法編譯?如果我將拷貝構造函數的訪問級別更改爲public,它將會正常並打印「Foo :: Foo(int)」。如果我寫「Foo實例(0);」而不是「Foo實例= 0;」它也會好的。爲什麼?這種行爲有什麼意義?帶有一個參數的私有拷貝構造函數和構造函數

#include <iostream> 

struct Foo 
{ 
public: 
    int i; 
    Foo(int i) : i(i) { std::cout << "Foo::Foo(int) \n"; } 

private: 
    Foo(const Foo&) { std::cout << "Foo::Foo(const Foo&) \n"; } 
}; 

int main() 
{ 
    Foo instance = 0; 
} 

回答

1

因爲

Foo instance = 0; 

拷貝初始化和需要訪問的拷貝構造函數。它嘗試使用轉換構造函數從0創建臨時Foo,然後使用複製構造函數從臨時Foo創建instance

相比之下,

Foo instance(0); 

直接初始化,只需要轉換構造函數。

相關:What's the motivation behind having copy and direct initialization behave differently?

+0

但它會打印出 「富::美孚(INT)」。它是編譯器優化嗎? – FrozenHeart

+1

@NikitaTrophimov是的,複製構造函數必須是可見的,但它不必被調用。 –

+0

@NikitaTrophimov請參閱http://stackoverflow.com/questions/12953127/what-are-copy-elision-and-return-value-optimization –

2

Foo instance = 0;使用拷貝初始化。使用非顯式構造函數Foo(int i)0轉換爲Foo對象,然後將其複製到instance。它相當於:

Foo instance = Foo(0); 

這需要您製作的複製構造函數。

當您將其設爲公共時,轉換構造函數打印的原因,但複製構造函數不打印是因爲複製可以被編譯器忽略優化。這是可能會改變代碼執行的一種優化形式。但是,複製構造函數仍然需要公開,不管它是否被刪除。換句話說,副本在可以被消除之前需要是可能的。

如果使轉換構造explicit,它不會編譯:

explicit Foo(int i) : i(i) { std::cout << "Foo::Foo(int) \n"; }