我想了解为什么 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
为什么这里必须忽略 B(int a, int b) 对 A(a) 的调用?我理解 C++ 标准要求它,但为什么呢?什么是理性?
如果我只实例化一个 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) 是子类对象,则 B(a,b) 的值与它是最派生对象时不同。这对我来说是非常混乱和错误的。有没有希望让足够多的人同意改变 C++ 标准?