class A{
public:
A(){};
};
class B : public A{
public:
using A::A;
B(const B&) = default;
B( B&&) = default;
};
B b;
编译器 (g++ (5.4.0-6ubuntu1) / c++11) 提示“没有匹配的函数可用于调用 B::B()”,并将复制和移动构造函数列为候选函数。如果我注释掉那些默认的,那么它就会编译。这是什么原因造成的?明确默认它们有什么区别?如果这两行不存在,它们无论如何都会被默认。
在 C++17 之前,基类的默认构造函数不会通过 using
继承:
所有候选继承构造函数(不是默认构造函数或复制/移动构造函数,且其签名与派生类中的用户定义构造函数不匹配)都在派生类中隐式声明。 (直到 C++17)
C++17 之后代码工作正常。
在此之前,默认构造函数不会从基类继承,并且不会为类B
生成
,因为提供了复制/移动构造函数。
如果没有为类类型(结构体、类或联合)提供任何类型的用户声明的构造函数,则编译器将始终将默认构造函数声明为其类的内联公共成员。这就是为什么如果您注释复制/移动构造函数,它就会编译。您可以显式添加定义作为 C++17 之前的解决方法。例如
class B : public A {
public:
B(const B&) = default;
B( B&&) = default;
B() = default;
};
代码使用gcc8进行编译。
隐式生成,您也可以通过为其添加= default
来生成它:
class B : public A {
public:
B() = default;
B(const B&) = default;
B( B&&) = default;
};
这已随
(*):
对于候选继承构造函数集中的每个非模板构造函数这意味着对于默认构造函数,正常规则适用,就好像除了构造函数 没有参数或者复制/移动构造函数只有一个参数,构造函数是隐式的 使用相同的构造函数特征进行声明,除非用户声明的构造函数具有相同的特征 使用声明出现的类中的签名。 ...
using A::A;
声明不存在一样。因此,任何其他构造函数声明(例如复制和移动构造函数)的存在都会导致默认构造函数不会被隐式声明。请注意,您可以通过明确默认它来轻松将其添加回来:
class B : public A{
public:
using A::A;
B() = default;
B(const B&) = default;
B( B&&) = default;
};
(*) C++14 (n4140) 中的相同位置存在相同的措辞。我似乎无法在 C++1z 中找到等效的措辞(查看 n4582)