我有以下类结构:
class A{
A(){}
A(const A& src){}
};
class B : virtual A {
B():A(){}
B(const B& src):A(src){}
};
class C : virtual A {
C():A(){}
C(const C& src):A(src){}
};
class D : virtual B, virtual C {
D():B(),C(){}
D(const D& src):B(src),C(src){}
};
这给了我警告:
在复制构造函数'D'中:
警告:应在副本中显式初始化基类“A” 构造
我不介意。
D的Copy -Constructor调用B的copy-ctor
,调用A的copy-ctor
。
为什么要我在D中调用A的copy-ctor
?
如果我这样做,A的copy-ctor
不会被叫两次吗?一旦从B调用并从D调用。
非常感谢对此的任何意见。
答案 0 :(得分:2)
现在我已经确认我是对的,B使用虚拟继承来从A派生。
当发生这种情况时,派生程度最高的类负责构造基类。这允许多重继承钻石。
======== A ============
^ ^
B C
\ /
\ /
\ /
\ /
D
D来自B和C,两者都来自A,因此D将继承A的2个副本,一个来自B,一个来自C。
如果B1和B2都使用虚拟继承从A派生,那么最终的类必须初始化基类,即A,从而确保只有一次实例。
这就是您收到错误消息的原因。
答案 1 :(得分:1)
D的Copy -Constructor调用B的copy-ctor,它调用A的副本。
不,它没有。虚拟基类始终由正在构造的最派生类初始化。继承层次结构中的类的成员初始值设定项列表中的初始化将被忽略,这些类不是构造中的对象的派生类最多的类。虚拟基类只能初始化一次,并且规则是最派生类将显式地或隐式地执行此操作,如果基类未出现在正在使用的最派生类构造函数的成员初始化程序列表中。
正如警告提示的那样,对于复制构造函数,您几乎肯定希望从正在复制的对象中显式初始化虚拟基类。
答案 2 :(得分:0)
原因是虚拟继承。因为A应该明确初始化。