我有以下代码:
#include <iostream>
#include <utility>
class A {
public:
A() { }
A(const A&, int i) { std::cout << "A copy" << std::endl; }
A(A&&, int i) { std::cout << "A move" << std::endl; }
A(const A&) = delete;
A(A&&) = delete;
};
class B : public A {
public:
B(int i) { std::cout << "B construct" << std::endl; }
B(const A& a) : A(a, 1) { std::cout << "B copy" << std::endl; }
B(A&& a) : A(std::move(a), 1) { std::cout << "B move" << std::endl; }
};
B make_b() {
return B(1);
}
int main() {
B b = make_b();
}
编译器错误报告错误B
无法复制构造(从make_b
返回),因为它没有复制构造函数,因为A
的复制构造函数被删除。
B(const A&)
不符合复制构造函数的要求,这里适用的规则是什么?B(const B&)
和B(B&&)
?答案 0 :(得分:4)
B(const A&amp;)是否不符合复制构造函数,这里适用的规则是什么?
没有。复制构造函数创建相同类型的另一个对象。 A
与B
的类型不同。如果您尝试从其基类的对象构造派生类的对象,那么您应该如何初始化派生类的成员?您要复制的源对象没有要复制的成员!
此外,B
已经有复制构造函数,由编译器隐式声明,但因为隐式定义不正确(因为基类A
是它是由编译器删除的,所以你不能使用它。
复制和移动构造函数是否总是必须使用相同类型的一个参数(而不是超类)?
不一定是一个参数,B(const B&, int = 0)
是复制构造函数,因为可以调用它来创建B
的副本。但是B(const A&)
不是复制构造函数。
是否可以使用默认值的其他参数?
是
要允许隐式复制和移动构造,是否有必要显式添加复制和移动构造函数
B(const B&)
和B(B&&)
?
是的,您需要显式定义它们,因为编译器将使用的隐式定义将不起作用。
由于派生类型没有任何成员,并且您已经拥有了A
的构造函数,因此您可以像这样定义它们:
B(const B& b) : B(static_cast<const A&>(b) { }
B(B&& b) : B(static_cast<A&&>(b) { }
这会创建委托构造函数,它只是将参数转发给现有的构造函数(使用适当的强制转换为基类型)。
答案 1 :(得分:0)
大约1: 在构造时,编译器从最高层到当前构造的类一个接一个地调用所有基类。 如果C继承自B继承自A 编译器调用A()然后调用B()而不是C()ctros来构建C对象。
复制构造函数也是如此: 在您的示例中,您调用A()复制构造函数来构建&#34; A&#34;对象的一部分,但你删除了它。
这里的问题是按值退出B,如果退出则调用第一个移动ctor,如果不退出则调用ctor。你删除了两个