隐式调用无法访问的虚拟基类的构造函数

时间:2015-02-27 18:02:38

标签: c++ c++11 gcc clang virtual-inheritance

请考虑以下代码。 g ++和clang ++都抱怨(正确地)构造函数A(int)在类D中是私有的。请注意,由于AD的虚拟基类,A必须在类D mem-initializer 中初始化,根据C ++ 11中的§12.6.2/ 7,派生最多的类。请参阅live example

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

class B : private virtual A {
protected:
    B(int i) : A(i) { } };

class C : public B, private virtual A {
protected:
    C(int i) : A(i), B(i) { }
};

class D : public C {
public:
    D() : A(1), C(3) { }
};

int main() {
    D d;
}

但是两个编译器都没有理会类A的默认构造函数在D中也是私有的,即,如果我们定义构造函数,则通常编译和执行代码D如下:

D() : C(3) {}

据我所知,这是错误的。

请注意,如果我们定义:

,两个编译器都无法正确编译
D() : A(), C(3) {}

1 个答案:

答案 0 :(得分:8)

  

但是两个编译器都没有理会类A的默认构造函数在D中也是私有的,

不,该默认构造函数不是私有的。基类A是私有的,但其默认构造函数是public。

这就是它的工作原理:在 ctor-initializer 中命名基类时,必须可以访问命名的基类,因为访问控制适用于名称,以及一些特殊的例外,其中标准说隐式调用的函数仍然必须是可访问的。

当隐式构造基类时,不会命名那些基类。它们只是默认初始化(每12.6.2p8),默认初始化只检查构造函数是否可访问(每8.5p7)。

您可以通过不使用基类的私有继承名称,但通过使用全局可访问的名称::A来判断问题是否与基类的名称有关:

D() : ::A(1), C(3) { }

Live example