MSVC 19删除继承的构造函数

时间:2019-02-28 15:34:54

标签: c++ c++11 visual-c++

在MSVC 19.16下,如果类B显式继承自类A的构造函数,并且还定义了自己的构造函数,则继承的构造函数将被忽略。

class A {
public:
    A() {}
    A(int x) {}
};

class B : public A {
public:
    using A::A;

    B(double x) : A() {}
};

int main()
{
    B b;                 // error C2512: 'B': no appropriate default constructor available
                         // note: see declaration of 'B'
    return 0;
}

在gcc下正确编译。 有人知道这是编译器错误还是我想念的东西?谢谢。

3 个答案:

答案 0 :(得分:5)

可以说不是错误。

  

C ++ 14 [class.inhctor]¶3

     

对于继承的构造函数候选集中的每个非模板构造函数,除了没有参数的构造函数或具有单个参数的复制/移动构造函数之外,构造函数都隐含地声明为相同的构造函数特征...

因此,在C ++ 17之前,默认构造函数不可继承,并且您的示例格式错误。

P0136删除了整个[class.inhctor]部分,并将用于继承构造函数的措词放在[namespace.udecl]中时,情况发生了变化。它被投票给C ++ 17,但是由于它是缺陷解决方案的一部分,因此允许实施者追溯地将其应用于该标准的先前版本。

因此,您的示例是有效的C ++ 17,并且潜在地有效的C ++ 11和C ++ 14,具体取决于您的编译器供应商是否已选择在根据这些要求进行编译时追溯应用此更改标准的修订版。合格的编译器在C ++ 17模式下进行编译时必须接受此示例,并且在其以C ++ 11或C ++ 14模式进行编译时有权接受或拒绝此示例,具体取决于供应商的决定。

CWG2273也可能相关。

请注意,在您的示例中,MSVC 19.16仅忽略了A::A()。它不会忽略A::A(int x)

答案 1 :(得分:0)

如果我们指定/std:c++14,它仍然会编译并显示错误。但是/std:c++17/std:c++latest使其可以编译。 因此,这似乎是MSVC中的错误。

答案 2 :(得分:0)

我想这是MSVC 19.16编译器错误。

如果你写

class B : public A {
    B(double) : A() {}
};

// ...

B b;

您应该从每个编译器中得到一个错误,因为B(double)构造函数会删除默认的B()构造函数。

但是,根据this page(查找“继承构造函数”)

  

如果using-declaration引用的是所定义类的直接基础的构造函数(例如,使用Base :: Base;),则初始化该基础时,该基础的所有构造函数(忽略成员访问)对于过载解析都是可见的。派生类。

     

如果重载解析选择了一个继承的构造函数,则在构造相应基类的对象时可以访问它,如果可以访问它,则可以访问它:引入它的using声明的可访问性将被忽略。

     

如果初始化此类派生类的对象时重载分辨率选择了一个继承的构造函数,则使用继承的构造函数初始化从其继承构造函数的Base子对象,并像初始化所有其他基类和Derived成员一样初始化由默认的默认构造函数(如果提供,则使用默认成员初始化程序,否则将进行默认初始化)。整个初始化被视为一个函数调用:在初始化派生对象的任何基数或成员之前,对继承的构造函数的参数进行初始化的过程是有序的。

因此,在这种情况下,using A::A;声明应该转换A构造函数中的B构造函数。

另一个例子。

仅使用接收B的构造函数来定义std::string

class B : public A {
public:
    using A::A;

    B(std::string) : A() {}
};

应该可以用整数初始化B

B  b(1);

因为A(int)构造函数是作为B构造函数继承的。