当存在移动和复制构造函数时,C++ 默认构造函数不会通过“using”继承

问题描述 投票:0回答:3
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++ c++11 constructor language-lawyer c++17
3个回答
11
投票

在 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进行编译。


6
投票
如果您声明任何构造函数,则默认构造函数不会

隐式生成,您也可以通过为其添加= default

来生成它:

class B : public A { public: B() = default; B(const B&) = default; B( B&&) = default; };
这已随 

C++17 改变(如 other 答案所指出)。


3
投票
默认构造函数不能被继承,标准明确这么说。引用 C++11 12.9 [class.inhctor]/3 (强调我的)

(*):

对于候选继承构造函数集中的每个非模板构造函数

除了构造函数 没有参数或者复制/移动构造函数只有一个参数,构造函数是隐式的 使用相同的构造函数特征进行声明,除非用户声明的构造函数具有相同的特征 使用声明出现的类中的签名。 ...

这意味着对于默认构造函数,正常规则适用,就好像

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)

© www.soinside.com 2019 - 2024. All rights reserved.