为什么虚拟继承需要在 B 和 C 执行,即使歧义在 D?如果它在 D 处会更直观。
在您的示例中, B 和 Cvirtual
专门用于要求编译器确保只涉及 A 的一个副本。如果他们不这样做,他们实际上是在说“我需要我自己的 A 基类,我不希望与任何其他派生对象共享它”。这可能是至关重要的。
不想共享虚拟基类的示例
如果 A 是某种容器,则 B 从它派生并存储某种特定类型的对象 - 比如说“Bat”,而 C 存储“Cat”。如果 D 期望 B 和 C 独立提供有关蝙蝠和猫种群的信息,那么如果 C 操作对蝙蝠/与蝙蝠做了某事,或者 B 操作对/与猫做了某事,他们会感到非常惊讶。
想要共享一个虚拟基类的例子
假设 D 需要提供对 A 中的某些函数或数据成员的访问,例如“A::x”...如果 A 由 B 和 C 独立(非虚拟)继承,则编译器无法解析 D ::x 到 B::x 或 C::x 无需程序员明确地消除歧义。这意味着 D 不能用作 A,尽管派生链暗示的不是一个而是两个“is-a”关系(即如果 B“是”A,而 D“是”B,那么用户可以期望/需要使用 D,就好像 D“是”A)。
为什么标准委员会会这样设计这个功能?
virtual
继承存在是因为它有时很有用。它由 B 和 C 指定,而不是 D,因为它在 B 和 C 的设计方面是一个侵入性概念,并且对 B 和 C 的封装、内存布局、构造和销毁以及函数调度都有影响。
如果 B 和 C 类来自 3rd 方库,我们该怎么办?
如果 D 需要从两者继承并提供对 A 的访问,但 B 和 C 并非设计为使用虚拟继承且无法更改,则 D 必须负责将任何与 A API 匹配的请求转发给 B 和/ 或 C 和/或可选的另一个 A 它直接继承自(如果它需要可见的“是 A”关系)。如果调用代码知道它正在处理 D(即使通过模板),这可能是实用的,但是通过指向基类的指针对对象的操作将不知道 D 试图执行的管理,整个事情可能是很难做到正确。但这有点像说“如果我需要一个矢量而我只有一个列表怎么办”,“一把锯子而不是螺丝刀”......好吧,充分利用它或得到你真正需要的东西。
编辑:我的回答是指示 B 和 C 类,它们不应在创建派生对象时调用 A 的构造函数,因为它将由 D 调用。
这是其中的一个重要方面,是的。