为什么不使用只有一个虚拟继承的钻石继承呢

Why not diamond inheritance with only one virtual inheritance?

本文关键字:继承 钻石 虚拟 有一个 为什么不      更新时间:2023-10-16

假设我们有经典的多重继承模式:

class Base {
    int baseMember;
};
class A : public Base {
    int aMember;
};
class B : public Base {
    int bMember;
};
class Derived : public A, public B {
    int derivedMember;
};

这将在内存中布局派生对象,如下所示:

  • 基本字段<--(基础*)(A*)这个
  • A的字段
  • 基本字段<--(基数*)(B*)这个
  • B的字段
  • 派生的字段

为了防止Base的字段重复,默认方法是从A和B:虚拟继承Base

class A : public virtual Base {
...
class B : public virtual Base {

这将导致以下布局:

  • 到基字段的偏移量<--(A*)这个|这个
  • A的字段
  • 到基字段的偏移量<--(B*)这个
  • B的字段
  • 派生的字段
  • 基本字段<--(基数*)这个|(基数*

这解决了这个问题,同时还需要应用偏移量来从其他类访问Base的字段(和虚拟函数)。

但为什么以下不可能呢?

  • 基本字段<--(基数*)(B*)这个|(基数*
  • A的字段
  • 到基字段的偏移量<--(B*)这个
  • B的字段
  • 派生的字段

这将允许A和Derived在没有开销的情况下访问Base,没有重复,甚至可以将大小缩小1个整数。但是,如果我尝试,编译器仍然会复制Base的字段(将它们放在B的字段后面)。

注意:我知道有人问过类似的问题,但我没有看到为什么这不可能。

编辑:4年后回过头来看,这可能与Derived中的"对Base字段的偏移"必须为负有关。

在看到Derived之前,您需要先布局A和B。一旦你选择了布局,它就会被固定在石头上。派生类和所有其他类必须将其用于其A和B子对象。(每个完整类的虚拟基准位置可能不同,不被视为布局的一部分)。

现在,在虚拟继承的情况下,A是如何布局的?它必须包含基本字段的偏移量,因为我们不知道A将如何在程序的其他部分中使用。它可能是一些尚未编写的派生类的第一个基类,也可能是第七个基类。但是,使用A的函数现在必须有一种方法将A转换为Base,而无需等待这些派生类的定义。

B.当然也是如此

因此,A和B都有自己的偏移集到Base字段。Derived不能做出其他决定,因为它可能不是唯一继承a或B的类。