请考虑以下代码。 g ++和clang ++都抱怨(正确地)构造函数A(int)
在类D
中是私有的。请注意,由于A
是D
的虚拟基类,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) {}
答案 0 :(得分:8)
但是两个编译器都没有理会类
A
的默认构造函数在D
中也是私有的,
不,该默认构造函数不是私有的。基类A
是私有的,但其默认构造函数是public。
这就是它的工作原理:在 ctor-initializer 中命名基类时,必须可以访问命名的基类,因为访问控制适用于名称,以及一些特殊的例外,其中标准说隐式调用的函数仍然必须是可访问的。
当隐式构造基类时,不会命名那些基类。它们只是默认初始化(每12.6.2p8),默认初始化只检查构造函数是否可访问(每8.5p7)。
您可以通过不使用基类的私有继承名称,但通过使用全局可访问的名称::A
来判断问题是否与基类的名称有关:
D() : ::A(1), C(3) { }