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

时间:2017-06-13 13:02:42

标签: c++ c++11 constructor language-lawyer c++17

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()的匹配函数”,并将复制和移动构造函数列为候选。如果我评论那些默认的那些,那么它就会编译。是什么导致这个?它们明显违约有什么区别?如果不存在这两行,那么无论如何它们都会被默认。

3 个答案:

答案 0 :(得分:8)

在C ++ 17之前,基类的默认构造函数不是inherited来自using

  

所有候选继承的构造函数都不是默认构造函数或复制/移动构造函数,并且其签名与派生类中的用户定义构造函数不匹配,在派生类中隐式声明。 (直到C ++ 17)

在C ++ 17之后,代码工作正常。

在此之前,默认构造函数不会从基类继承,并且对于类B不会是generated,因为提供了复制/移动构造函数。

  

如果没有为类类型(struct,class或union)提供任何类型的用户声明的构造函数,编译器将始终将默认构造函数声明为其类的内联公共成员。

这就是为什么如果你评论复制/移动构造函数,它编译。您可以将该定义明确添加为C ++之前的17种解决方法。 e.g。

class B : public A {
public:
    B(const B&) =   default;
    B(      B&&) =  default;

    B() = default;
};

代码用gcc8编译。

答案 1 :(得分:5)

如果声明任何构造函数,则默认构造函数不是implicitly generated,您也可以通过为其添加= default来生成它:

class B : public A {

public:

    B() = default;
    B(const B&) =   default;
    B(      B&&) =  default;
};
  

C++17已经改变了(正如other回答所指出的那样)。

答案 2 :(得分:3)

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

  

对于继承构造函数的候选集中的每个非模板构造函数,而不是构造函数   没有参数或具有单个参数的复制/移动构造函数,构造函数是隐式的   声明具有相同的构造函数特征,除非有一个用户声明的构造函数具有相同的构造函数   出现using声明的类中的签名。 ...

这意味着对于默认构造函数,正常规则适用,就像using A::A;声明不存在一样。因此,任何其他构造函数声明(例如copy和amp; move构造函数)的存在都会导致默认构造函数不被隐式声明。请注意,您可以通过明确默认将其轻松添加回来:

class B : public A{

public:
    using A::A;

    B() = default;

    B(const B&) =   default;
    B(      B&&) =  default;

};

(*)在C ++ 14(n4140)中,在同一位置存在相同的措辞。我似乎无法在C ++ 1z中找到相同的措辞(通过n4582查看)