为什么除非大多数派生基显式调用虚基非默认构造函数,否则不会调用它们? 我想理解为什么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; }

为什么除非大多数派生基显式调用虚基非默认构造函数,否则不会调用它们? 我想理解为什么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; },c++,constructor,c++17,virtual-inheritance,ctor-initializer,C++,Constructor,C++17,Virtual Inheritance,Ctor Initializer,但是,当使用-D_和_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)

但是,当使用-D_和_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
为什么在这里必须忽略B(inta,intb)对a(a)的调用? 我理解C++标准的任务,但是为什么?什么是理性

如果我仅实例化一个B对象: B(4,5); 这确实得到了正确的b.(u a值4;但如果B是C的一个子类: C(4,5,6) a最终为1,如果C不直接调用a(a)。 因此,如果它是一个子类对象,那么B(a,B)的值是不同的 如果它是最派生的对象。 这对我来说是非常混乱和错误的。有希望得到什么吗
有足够的人同意更改C++标准吗?

< p>这个行为是因为<代码>虚拟基类< /C>。因为A是虚拟基类,所以它是由最派生的类构造的。
您可以查看并了解为什么必须采用这种方式。
首先了解如何通过虚拟基类解决diamod形状问题。
A类{…}

B类:虚拟公共A{…}

C类:虚拟公共A{…}

D类:公共B、公共C{…}


将基类设置为虚拟时,将有一个基类对象。中间派生类对象都将引用同一个基类对象。也就是说,如果创建了
D
的对象,那么B::A和C::A都将引用同一个对象。这个单一对象是B和C的基类。因此,如果它允许通过中间类构造基类对象,则有两个派生类来构造这个单一对象。通过赋予派生最多的类构造虚拟基类的责任,可以解决这种模糊性

您不太可能获得任何支持来更改语言。虚拟继承仅在多继承场景中有用

为什么在这里必须忽略B(inta,intb)对a(a)的调用

因为已经构造了唯一的子对象。构造函数不是一个普通函数,你不能在任何地方调用它

你可以写

C(int a, int b, int c)
    : A(a), B(a, b), _c(c)
    { ... }

这将为
B::B(int,int)
的主体提供传递给
A::A(int)

的参数。虚拟继承的全部目的是解决问题。一旦有了虚拟基类,层次结构如下所示:

  A
 / \
B   C
 \ /
  D
您需要知道何时构造
A
。你不能让
B
构造它然后
C
然后立即覆盖它-你需要构造它一次。好的,那我们什么时候可以做?最简单的选择就是:让最派生的类这样做!因此,当我们初始化
D
B
子对象时,它不会初始化其
A
子对象,因为
B
不是最派生的类型

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

A
|
B
|
C

但是最派生的类型,
C
,必须初始化所有虚拟基-
A
B
B
不会初始化其
A
子对象,原因与在复杂示例中没有初始化的原因相同。

能否将代码的格式设置得更好一些?当前的编写方式很混乱。“虚拟基非默认构造函数”构造函数不能是虚拟的。@Raket1111我认为它应该被理解为虚拟基非默认构造函数:)这不是问题,而是以下划线开头,后跟大写字母(
\u with_BUG\u
)的名称并且包含两个连续下划线的名称保留供实现使用。不要在代码中使用它们;规则是虚基由最派生类型的构造函数初始化。这适用于默认构造函数和非默认构造。对我来说,这是KrdGey,程序员必须记住它们的B(A,B)的显式调用被忽略。另一个选项是不实际继承纠正,这并不能真正解释理论,只是C++标准规定了它。嗯,一旦一个程序员宣布B实际上是或不是a,那么B就应该负责构造它的“a”。我仍然看不出为什么B不能总是构造它的a,不管它是否是某个C类的虚拟基。但我必须接受它是这样的…“它的‘A’”->与所有其他类共享,这些类实际上在派生中继承了Aclass@JVD这里B不能构造“A”,因为A是一个虚拟基,派生最多的类C必须构造它。钻石问题就是这样解决的。你可以查看post链接。如果您看到中间类构造虚拟基类,那么所有中间类都需要构造单个虚拟基类对象。
A
|
B
|
C