隐式调用不可访问的虚拟基础的构造函数 class
Implicitly calling a constructor of an inaccessible virtual base class
考虑下面的代码。 g++ 和 clang++ 都抱怨(正确地)构造函数 A(int)
在 class D
中是私有的。请注意,由于 A
是 D
的虚拟基础 class,因此 A
必须在 mem-initializer 中初始化class D
,最派生的 class,根据 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;
}
但是两个编译器都不会理会 class A
的默认构造函数在 D
中也是私有的,即正常编译和执行代码,如果我们如下定义 D
的构造函数:
D() : C(3) {}
据我所知,这是错误的。
请注意,如果我们定义:
,两个编译器都无法(正确)编译
D() : A(), C(3) {}
But both compilers don't bother with the fact that the default constructor for class A
is also private in D
,
不,默认构造函数不是私有的。基础 class A
是私有的,但它的默认构造函数是 public.
这就是它起作用的原因:在 ctor-initializer 中命名基 classes 时,命名的基 classes 必须是可访问的,因为访问控制适用于名称,以及一些特殊的例外情况,其中标准规定隐式调用的函数仍然必须是可访问的。
当基 classes 被隐式构造时,那些基 classes 不被命名。它们只是默认初始化(根据 12.6.2p8),默认初始化仅检查构造函数是否可访问(根据 8.5p7)。
您可以通过不使用基的私有继承名称 class 而是使用可全局访问的名称 ::A
来判断问题出在基的名称 class ]:
D() : ::A(1), C(3) { }
考虑下面的代码。 g++ 和 clang++ 都抱怨(正确地)构造函数 A(int)
在 class D
中是私有的。请注意,由于 A
是 D
的虚拟基础 class,因此 A
必须在 mem-initializer 中初始化class D
,最派生的 class,根据 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;
}
但是两个编译器都不会理会 class A
的默认构造函数在 D
中也是私有的,即正常编译和执行代码,如果我们如下定义 D
的构造函数:
D() : C(3) {}
据我所知,这是错误的。
请注意,如果我们定义:
,两个编译器都无法(正确)编译D() : A(), C(3) {}
But both compilers don't bother with the fact that the default constructor for class
A
is also private inD
,
不,默认构造函数不是私有的。基础 class A
是私有的,但它的默认构造函数是 public.
这就是它起作用的原因:在 ctor-initializer 中命名基 classes 时,命名的基 classes 必须是可访问的,因为访问控制适用于名称,以及一些特殊的例外情况,其中标准规定隐式调用的函数仍然必须是可访问的。
当基 classes 被隐式构造时,那些基 classes 不被命名。它们只是默认初始化(根据 12.6.2p8),默认初始化仅检查构造函数是否可访问(根据 8.5p7)。
您可以通过不使用基的私有继承名称 class 而是使用可全局访问的名称 ::A
来判断问题出在基的名称 class ]:
D() : ::A(1), C(3) { }