c++ - C++ 为什么不调用虚基构造函数,除非大多数派生基显式调用它们?

  显示原文与译文双语对照的内容

我想理解为什么 C++ 标准要求虚拟基非默认构造函数在使用'-d_with_bug _'编译时不能被中间的派生类调用:


/* A virtual base's non-default constructor is NOT called UNLESS 


 * the MOST DERIVED class explicitly invokes it


 */



#include <type_traits>


#include <string>


#include <iostream>



class A


{


public:


 int _a;


 A(): _a(1)


 {


 std::cerr <<"A() - me:" <<((void*)this) <<std::endl;


 }


 A(int a): _a(a)


 {


 std::cerr <<"A(a) - me:" <<((void*)this) <<std::endl;


 }


 virtual ~A()


 {


 std::cerr <<"~A" <<((void*)this) <<std::endl;


 }


};



class B: public virtual A


{


public:


 int _b;


 B(): A(), _b(2)


 {


 std::cerr <<"B() - me:" <<((void*)this) <<std::endl;


 }


 B(int b) : A(), _b(b)


 {


 std::cerr <<"B(b) - me:" <<((void*)this) <<std::endl;


 }


 B(int a, int b): A(a), _b(b)


 {


 std::cerr <<"B(a,b) - me:" <<((void*)this) <<std::endl;


 }


 virtual ~B()


 {


 std::cerr <<"~B" <<((void*)this) <<std::endl;


 }


};



class C: public virtual B


{


public:


 int _c;


 C(): B(), _c(3)


 {


 std::cerr <<"C()" <<std::endl;


 }


 C(int a, int b, int c)


 :


#ifdef _WITH_BUG_ 


 B(a,b)


#else


 A(a), B(b)


#endif 


, _c(c)


 {


 std::cerr <<"C(a,b) - me:" <<((void*)this) <<std::endl; 


 }


 virtual ~C()


 {


 std::cerr <<"~C" <<((void*)this) <<std::endl;


 } 


};


extern"C"


int main(int argc, const char *const* argv, const char *const* envp)


{


 C c(4,5,6);


 std::cerr <<" a:" <<c._a <<" b:" <<c._b <<" c:" <<c._c 


 <<std::endl;


 return 0;


}



因此,如果没有-D_WITH_BUG_编译,代码将打印:


$ g++ -I. -std=gnu++17 -mtune=native -g3 -fPIC -pipe -Wall -Wextra 


 -Wno-unused -fno-pretty-templates -Wno-register 


 tCXX_VB.C -o tCXX_VB 


$./tCXX_VB


A(a) - me:0x7ffc410b8c10


B(b) - me: 0x7ffc410b8c00


C(a,b) - me: 0x7ffc410b8bf0


a: 4 b: 5 c: 6


~C0x7ffc410b8bf0


~B0x7ffc410b8c00


~A0x7ffc410b8c10



但使用-D_WITH_BUG_编译时:


$ g++ -I. -std=gnu++17 -mtune=native -g3 -fPIC -pipe -Wall -Wextra  


 -Wno-unused -fno-pretty-templates -Wno-register 


 -D_WITH_BUG_ tCXX_VB.C -o tCXX_VB


$./tCXX_VB


A() - me: 0x7ffd7153cb60


B(a,b) - me: 0x7ffd7153cb50


C(a,b) - me: 0x7ffd7153cb40


a: 1 b: 5 c: 6


~C0x7ffd7153cb40


~B0x7ffd7153cb50


~A0x7ffd7153cb60



为什么在这里必须忽略 A(a)的( int的int调用)? 我理解 C++ 标准规定了它,但是为什么? 理性是什么?

如果我只实例化一个B 对象: B b(4,5) ;这样做得到正确的b._a 值 4 ;但如果B 是 C: C c(4,5,6) C::a的子类,则C 不直接调用 A(a) 。 因这里,如果它是一个子类对象,则 B(a,b)的值是不同的,比如它是最。 这对我来说是非常混乱和错误的。 是否有希望获得足够的人同意更改 C++ 上的标准?

时间: 原作者:

虚拟继承的全部目的是解决钻石问题的问题。 当你拥有一个虚拟基类,并且你的层次结构如下所示:


 A


/


B C


/


 D



你需要知道,当你去构造 A 时。 你不能使用 B 构造它,然后 C 立即覆盖它- 你需要它完全构造一次。 那么我们什么时候可以? 最简单的选择是: 使最派生的类执行它 ! 因此当我们初始化 DB 子对象时,它不会,因为 B 不是最派生的类型,因为它不是最派生的类型。

在你的情况下,你的层次结构仍然是线性的:

 
A


|


B


|


C



 

但最派生的类型 C 必须初始化所有虚拟基- ABB 不会像在复杂示例中那样初始化它的A 子对象。

原作者:
...