理解派生类中的vtable

时间:2017-05-24 08:09:49

标签: c++ oop inheritance vtable vptr

我试图通过虚拟表和继承来解决一些低级别的问题。

当你通过继承两个类并添加新的虚函数来创建新类时,vptr究竟会存储在哪里?

在我看来,编译器会执行一些' vptr-optimization'在这种情况下。我试图解决这个问题。

假设我们有以下结构:

struct A
{
  int a;
  virtual void fa();
};
struct B
{
  double b;
  virtual void fb();
};
struct C : A, B
{
  char c;
  virtual void fa();
  virtual void fb();
  virtual void fc();
};

如果x86和align = 4,内存中的AB将如下所示:

   +------+------+
A: | vptr |  a   |
   +------+------+
sizeof(A) = 4 + 4 = 8

   +------+------+------+------+
B: | vptr        |      b      |
   +------+------+------+------+
sizeof(B) = 8 + 8 = 16

但是当我尝试重新组装C时,我明白了:

   +------+------+------+------+------+------+------+
C: | vptr |  a   | vptr        |      b      |  c   |
   +------+------+------+------+------+------+------+
but sizeof(C) = 32

С с;
(C*)&c; // 0x100
(B*)&c; // 0x108
(A*)&c; // 0x100
&c.a;   // 0x104
&c.b;   // 0x110
&c.c;   // 0x118

那么C的vptr在哪里?我可以假设编译器合并了不同的虚拟表(例如AC的vptr),但在这种情况下,为什么sizeof(C)会返回sizeof(A) + sizeof(B) + sizeof(alligned_char) + sizeof(vptr)

struct D : public C {}有相同的故事 - 没有D的vptr。

我使用的编译器是msvc 2012 x86。

1 个答案:

答案 0 :(得分:4)

编译器必须兼顾简单性,因为基类需要存在于对象中。

+------+---------+----+
|   A  | B       |  C |
+------+---------+----+

所以

  • A需要存在,好像它不是派生的。
  • B需要存在,好像它不是派生的。
  • C有新的自由。

来自A和B的虚拟函数将针对派生类C的实现进行修补。 C将向(可能)现有的第一个元素A vtable添加虚函数。

A的基础vtable

+------+
| A:fa |
+------+

派生类A

C的vtable
+------+
| C:fa |   // implemented by derived class.
+------+
| C:fb |   // any calls to fb need to be sent to `C`'s implementation
+------+
| C:fc |   // any calls to fc can be overridden by vtable.
+------+ 

派生类B

C的vtable
+------+
| C:fb |   // overridden, but no need to add fc, fa to this table.
+------+

我认为对齐规则会导致C的大小被填充,因此对齐敏感的double正确对齐(确保C的数组正确对齐)。

B的大小是vptr(4)的大小和填充,以确保double对齐(4)和double的大小( 8)

相关问题