c++ - C++中的虚拟继承和统一初始化

标签 c++ c++11 inheritance gcc c++14

跟进 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. 代码在某种程度上违反了标准,导致结果不确定(即任何结果都是可以接受的)。
  2. 两个编译器中的一个存在与统一初始化和多重 + 虚拟继承相关的错误。

如果是投票问题,(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) — If T is a class type and the initializer list has a single element of type cv U [..]
(3.2) — Otherwise, if T 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 and T is a class type with a default constructor, the object is value-initialized.

AB 都有基类,因此不是聚合。因此第四点适用。因此我们得到了与使用 () 完全相同的效果:

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/

相关文章:

c++ - lua_getfield 的奇怪行为

java - 读取.class文件

c++ - 成员初始值设定项中使用的 sizeof 的行为是什么?

c++ - 在 C++ 工厂中删除实例

c++ - 方法中的静态局部变量是一种不好的做法?

c++ - Visual Studio npcc64_60.dll 陷阱?

c++ - 静态库中对 c++11 原子的 undefined reference

c++ - 为什么std::lock_guard在使用std::adopt_lock之后释放锁?

c++ - 如何使用动态绑定(bind)继承适当的类?

c++ - 继承中的虚拟调用