为什么除非大多数派生基显式调用它们,否则不调用虚拟基非默认构造函数? [英] why are virtual base non-default constructors not called unless most-derived base explicitly invokes them?
问题描述
我想了解WHY C ++标准的要求,即虚拟基础非默认构造函数不能由非最衍生的中间层调用 此类代码中的类,当使用'-D_WITH_BUG_'编译时:
I would like to understand WHY C++ standard mandates that virtual base non-default constructors cannot be invoked by an intermediate NOT most-derived class, as in this code, when compiled with '-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_进行编译时,代码将输出:
So, when compiled WITHOUT -D_WITH_BUG_, the code prints:
$ 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_编译时:
But when compiled with -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
为什么在这里必须忽略B(int a,int b)对A(a)的调用? 我了解C ++标准的要求,但是为什么呢?有理是什么?
Why must B(int a, int b)'s invocation of A(a) be ignored here ? I understand the C++ standard mandates it, but why ? What is the rational ?
如果我仅实例化一个B对象: B b(4,5); 确实得到正确的b._a值为4;但是如果B是C的子类: C c(4,5,6) C :: a最终为1,IFF c不直接调用A(a). 因此,如果B(a,b)是子类对象,则其值是不同的 比它是一个最派生的对象. 这对我来说是非常混乱和错误的.有没有希望 足够多的人同意在此基础上更改C ++标准?
If I instantiate just a B object : B b(4,5) ; this DOES get a correct b._a value of 4; but if B is a subclass of C: C c(4,5,6) C::a ends up being 1, IFF c does not DIRECTLY INVOKE A(a) . So the value of a B(a,b) is different if it is a subclass object than if it is a most-derived object . This to me is very confusing and wrong. Is there any hope of getting enough people to agree to change the C++ standard on this ?
推荐答案
拥有虚拟继承的全部目的是解决钻石问题.一旦有了虚拟基类,您的层次结构将如下所示:
The entire purpose of having virtual inheritance is to solve the diamond problem. Once you have a virtual base class, and your hierarchy looks like this:
A
/ \
B C
\ /
D
您需要知道何时构造A
.您不能先B
构造它,然后C
然后立即覆盖它-您需要将它构造一次.好的,那我们什么时候可以做?最简单的选择就是:让最派生的类来做!因此,当我们初始化D
的B
子对象时,它不会初始化其A
子对象,因为B
不是最派生的类型.
You need to know when to construct the A
. You can't have B
construct it and then C
then immediately overwrite it - you need it to be constructed exactly once. Okay, so when can we do that? The simplest choice is just: make the most derived class do it! So when we're initializing the B
subobject of D
, it will not initialize its A
subobject because B
is not the most derived type.
在您的情况下,您的层次结构仍然是线性的:
In your case, your hierarchy is still linear:
A
|
B
|
C
,但最派生的类型C
必须初始化所有虚拟基数-A
和B
. B
不会出于复杂示例中未初始化的原因而初始化其A
子对象.
but the most derived type, C
, has to initialize all the virtual bases - A
and B
. B
won't initialize its A
subobject for the same reason as it didn't in the complicated example.
这篇关于为什么除非大多数派生基显式调用它们,否则不调用虚拟基非默认构造函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!