隐式转换和复制构造函数

Alb*_*dez 4 c++

更新:建议重复的唯一解决这个问题的一部分.理解发生了什么的关键(首次创建临时引用的事实)在那里没有解释.

这是我第一次使用隐式转换,所以我写了这个:

class A {};

class B {
public:
    B(A& other) {}
    // Copy constructor
    B(const B& other) {}
};

int main() {
    A foo;
    B bar = foo;
}
Run Code Online (Sandbox Code Playgroud)

这按预期编译,但是如果我删除了const,我的编译器(gcc版本4.8.4)在赋值时产生,带有错误消息我无法理解:

test.cc: In function ‘int main()’:
test.cc:12:13: error: no matching function for call to ‘B::B(B)’
     B bar = foo;
             ^
test.cc:12:13: note: candidates are:
test.cc:7:5: note: B::B(B&)
     B(B& other) {}
     ^
test.cc:7:5: note:   no known conversion for argument 1 from ‘B’ to ‘B&’
test.cc:5:5: note: B::B(A&)
     B(A& other) {}
     ^
test.cc:5:5: note:   no known conversion for argument 1 from ‘B’ to ‘A&’
Run Code Online (Sandbox Code Playgroud)

这是有效的C++代码吗?为什么no matching function for call to ‘B::B(B)’当我尝试分配一个A开头时呢?

Vla*_*cow 7

这个宣言

B bar = foo;
Run Code Online (Sandbox Code Playgroud)

按以下方式工作:

首先,编译器使用构造函数创建一个临时对象:

B(A& other) {}
Run Code Online (Sandbox Code Playgroud)

然后它尝试在复制构造函数中使用此临时对象:

B(B& other) {}
Run Code Online (Sandbox Code Playgroud)

但是它可能不会使用非常量引用绑定临时对象,并且会发出错误.

当您使用等号时,则使用所谓的复制初始化.

如果你写的

B bar( foo );
Run Code Online (Sandbox Code Playgroud)

那么这里将使用所谓的直接初始化,即不调用复制构造函数.在这种情况下,此代码将编译.

考虑到可以绕过复制/移动构造函数,并且可以直接在目标对象中构建临时对象.这称为复制省略.尽管如此,所有规则都应保留,就像明确调用复制/移动构造函数一样.

例如,如果为类B的构造函数添加输出语句

class A {};

class B {
public:
    B(A& other) { std::cout << "B::B( A & )" << std::endl; }
    // Copy constructor
    B(const B& other) { std::cout << "B::B( const B & )" << std::endl; }
};

int main()
{
    A foo;
    B bar = foo;
}
Run Code Online (Sandbox Code Playgroud)

那你就看不到消息了

B::B( const B & )
Run Code Online (Sandbox Code Playgroud)

但是复制构造函数应该是可访问的.

例如,如果您将其设为私有

class A {};

class B {
public:
    B(A& other) { std::cout << "B::B( A & )" << std::endl; }
    // Copy constructor
private:
    B(const B& other) { std::cout << "B::B( const B & )" << std::endl; }
};

int main()
{
    A foo;
    B bar = foo;
}
Run Code Online (Sandbox Code Playgroud)

程序不会编译(只有它不是MS VC++编译器.:))


0x4*_*2D2 5

B bar = foo被称为复制初始化:当右手边的类型不匹配的左手边的类型(在这种情况下,BVS A)编译器创建一个临时从右侧初始化,然后使用它的副本拷贝构造函数.这实际上是你的代码:

B bar = B(foo);
Run Code Online (Sandbox Code Playgroud)

由于您已从const复制构造函数中删除,因此您现在会收到错误,因为您尝试将右值绑定到左值引用.const正如您已经看到的那样,Rvalues可以绑定到左值引用.

这可以通过使用直接初始化来解决.现在没有创建副本:

B bar(foo);
Run Code Online (Sandbox Code Playgroud)