【问题标题】:Size of most derived class in virtual inheritance虚拟继承中大多数派生类的大小
【发布时间】:2020-02-01 16:18:58
【问题描述】:

在下面的代码中,为什么D 的大小是16 而不是8 字节?

我认为因为我们有虚拟基类,所以应该只有一个A 的实例。

class A
{
public:
    int x_;
    int y_;
};

class B :  virtual public A
{
};

class C :  virtual public A
{

};

class D :  public B, public C
{
};

【问题讨论】:

  • 对于聚合类型的大小和布局的任何问题,请先给出您机器上基本类型的大小。
  • 他们还需要一些方法来访问那个实例,通常是保存一个指针或偏移量。
  • 您可以通过Compiler Explorer回答您的问题及更多内容。

标签: c++ multiple-inheritance sizeof virtual-inheritance memory-layout


【解决方案1】:

我认为因为我们有虚拟基类,所以应该只有一个 A 实例。

没错。

在下面的代码中,为什么 D 的大小是 16 而不是 8 字节?

在我的系统上,D 是 24 字节。

D 包含一个 B 子对象(不包括 A)、一个 C 子对象(不包括 A)和一个虚拟 A 子对象。

由于基不是标准布局,因此不需要空基优化,并且每个基都有唯一的地址,因此尽管本身没有子对象,但仍会占用内存。

此外(取决于您的编译器如何实现虚拟基),虚拟继承需要使用虚拟表来访问虚拟基,因此实例将具有指向该表的虚拟指针。

【讨论】:

  • "尽管本身没有子对象。" 你是什么意思? “使用虚拟表来处理共享库的构建”是怎么回事?
  • @curiousguy "despite having no subobjects themselves." what do you mean? 他们没有成员,由于是虚拟的,他们唯一的基地不在他们内部。 "the use of a virtual table to handle the construction of the shared base" how so? 也许描述有点有限,因为它可能不仅仅是关于建筑,而是一般访问虚拟基地。此外,这特别适用于安腾 ABI;我不知道非 Itanium-ABI 编译器如何处理虚拟库。
  • 我记得MSVC使用(使用过?)内部ptr;这当然使其二进制与“Itanium-ABI”之后的编译器不兼容。
【解决方案2】:

在下面的代码中,为什么 D 的大小是 16 而不是 8 字节?

在任何情况下,所有这些派生类都不能(实际上是 (*))与它们的虚拟基 A 具有相同的大小:

  • 派生类对象与非虚拟直接基子对象的关系,就像与成员子对象的关系一样,是一对一的关系;
  • 派生类对象与虚拟基础子对象的关系是多对一关系:根据定义,特定虚拟基础子对象可以是多个派生类的直接基础。这里的A 基础子对象是D 对象(或另一个派生对象的子对象)的B 和C 子对象的直接基础。

(*) 我知道有可能违反该断言的实现方法,但它们的效率要低得多、笨拙、更难确保线程安全,甚至在线程程序中效率更低。

因为关系是多对一的,所以类布局不能固定(与非虚拟成员或成员不同)。唯一基础子对象的位置取决于创建的确切派生类。

X 类的 (g) 左值指的是 X 类型的实例或派生自 X 的类;因此,当使用不引用已知对象的此类 (g)lvalue 时(当使用本地声明的对象的名称时,定义的类型是已知的),基本子对象的地址在运行时从类型(或地址) 嵌入在实例中的信息。

所以B 和C 需要携带这些信息来定位虚拟基地。这使得它们比基地更大。最派生的类需要空间来存储所有非虚拟基中的位置信息,再加上虚拟基本身(如果它有任何数据成员,通常放在最后)。

【讨论】:

    猜你喜欢
    • 2013-02-26
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 2020-10-26
    • 2020-09-30
    • 2021-04-14
    • 1970-01-01
    相关资源
    最近更新 更多