跟进 this question about multiple (virtual) inheritance ,我想询问一个简单的 MWE,它使 g++ 5.2.0 不高兴,而 clang++ 3.6.2 处理得很好,没有任何提示,即使-Wall
和 -Wextra
设置。所以这是 MWE:
class Z {};
class A : virtual Z { protected: A() {} };
class B : virtual Z { protected: B() {} };
class C : A, B { public: C() : A{}, B{} {} };
int main() { C c{}; return 0; }
与 clang++ 不同,g++ 的报错是这样的:
gccodd.c++: In constructor ‘C::C()’:
gccodd.c++:2:34: error: ‘A::A()’ is protected
class A : virtual Z { protected: A() {} };
^
gccodd.c++:4:39: error: within this context
class C : A, B { public: C() : A{}, B{} {} };
^
gccodd.c++:3:34: error: ‘B::B()’ is protected
class B : virtual Z { protected: B() {} };
^
gccodd.c++:4:39: error: within this context
class C : A, B { public: C() : A{}, B{} {} };
^
虽然用旧形式替换 C 的构造函数中的统一初始化工作正常,但 clang++ 和 g++ 都对以下内容感到满意:
class C : A, B { public: C() : A(), B() {} };
这会产生两个明显的选择:
- 代码在某种程度上违反了标准,导致结果不确定(即任何结果都是可以接受的)。
- 两个编译器中的一个存在与统一初始化和多重 + 虚拟继承相关的错误。
如果是投票问题,(1) 可能会获胜,因为 icpc 15.0.0 说了以下内容:
gccodd.c++(4): error #453: protected function "A::A()" (declared at line 2) is not accessible through a "A" pointer or object
class C : public virtual A, public virtual B { public: C() : A{}, B{} {} };
^
gccodd.c++(4): error #453: protected function "B::B()" (declared at line 3) is not accessible through a "B" pointer or object
class C : public virtual A, public virtual B { public: C() : A{}, B{} {} };
^
那么,是 (1) 还是 (2)?如果是前一种情况,那么我的 MWE 出了什么问题?
最佳答案
List-initialization of an object or reference of type
T
is defined as follows:
(3.1) — IfT
is a class type and the initializer list has a single element of type cvU
[..]
(3.2) — Otherwise, ifT
is a character array [..]
(3.3) — Otherwise, if T is an aggregate, aggregate initialization is performed (8.5.1).
(3.4) — Otherwise, if the initializer list has no elements andT
is a class type with a default constructor, the object is value-initialized.
A
和 B
都有基类,因此不是聚合。因此第四点适用。因此我们得到了与使用 ()
完全相同的效果:
An object whose initializer is an empty set of parentheses, i.e.,
()
, shall be value-initialized.
任何使用这些初始值设定项产生不同结果的编译器都不能符合要求。
§11.4 处理对 protected
成员的访问,没有提及任何与初始化形式相关的内容。但是,关于构造函数中内存初始化器中基数的初始化,§11.4 目前有缺陷,如 CWG 问题 #1883 所述。 .
关于c++ - C++中的虚拟继承和统一初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32032249/