2012-11-26 46 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"; }