【问题标题】:Virtual class inheritance object size issue虚拟类继承对象大小问题
【发布时间】:2019-12-20 05:12:58
【问题描述】:

在这里,在这段代码中,ob1 的大小是 16,这很好(因为虚拟指针),但我不明白为什么 ob2 的大小是 24。

#include <iostream>
using namespace std;
class A {
    int x;
};
class B {
    int y, z;
};
class C : virtual public A {
    int a;
};
class D : virtual public B {
    int b;
};
int main() {
    C ob1;
    D ob2;
    cout << sizeof(ob1) << sizeof(ob2) << "\n";
}

我希望ob2的大小为20,但输出是24

【问题讨论】:

  • virtual 机制需要一些开销。一些编译器将这些开销放入结构中。
  • 您应该养成始终通过'\n'std::endl 终止输出的习惯。
  • 通常有一个vtable指针引入了虚拟继承。这或许可以解释大小的差异,
  • @πάνταῥεῖ:“通常有一个 vtable 指针”。虚拟继承是否引入了 vtable 指针?我不信!
  • 我希望 ob2 的大小为 20,但输出为 24 你的确切平台是什么?对象内部的某些东西可能有 8 字节对齐要求。或者平台本身通常会强制要求 8 字节对齐。

标签: c++ virtual-inheritance memory-layout vptr


【解决方案1】:

D 类型的对象的一种可能布局是:

+----------+
| y        |   The B subobject (8 bytes)
| z        |
+----------+
| vptr     |   vtable pointer (8 bytes)
|          |
+----------+
| b        |   4 bytes
+----------+
| unused   |   4 bytes (padding for alignment purposes)
+----------+

这将使sizeof(ob2) 24。

对齐要求由实现定义。大多数时候,最大成员对象或子对象的大小决定了对象的对齐要求。在您的情况下,最大对象的大小,即 vtable 指针,是 8 个字节。因此,该实现在 8 位边界对齐对象,并在必要时添加填充。

【讨论】:

  • 显然是正确的答案。也许您可以详细说明 for alignment purposes 位?
  • 我对这个问题很感兴趣:为什么在这种情况下我们需要运行时 vtable 指针。我无法理解为什么它在这里依赖于运行时,因为继承层次结构在编译时是完全已知的。谢谢...也许另一个问题:-)
  • @Klaus,是的,那将是另一个问题。
  • @Klaus 继承关系在编译时并不比函数成员更广为人知。与非虚拟的东西不同,虚拟的东西可以在派生类中被覆盖。
【解决方案2】:

为了实现虚拟继承,D 包含一个指针作为数据成员,在 64 位系统上需要 8 个字节。此外,这 8 个字节必须与 8 个字节的内存边界对齐。后一个要求反过来要求D 本身与 8 字节内存边界对齐。实现这一点的最简单方法是通过用未使用的字节 (21-24) 填充 sizeof(D) 来使 sizeof(D) 成为 8 的倍数。

【讨论】:

  • "用未使用的字节填充它",并且(几乎可以肯定是正确的)假设可以通过在末尾添加一个虚拟数据成员、假设填充的大小以及检查总大小没有改变。
猜你喜欢
  • 1970-01-01
  • 2023-03-22
  • 2010-09-28
  • 1970-01-01
  • 2019-10-11
  • 2020-10-31
  • 2013-02-26
  • 2012-10-11
相关资源
最近更新 更多