gpt4 book ai didi

c++ - 派生类中vtable的理解

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:36:43 24 4
gpt4 key购买 nike

我试图通过虚拟表和继承来理解一些低级的东西。

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

在我看来,编译器在那种情况下会执行一些“vptr 优化”。我正在努力弄清楚。

假设,我们有以下结构:

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。

最佳答案

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

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

所以

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

来自 A 和 B 的虚函数将被修补以用于派生类 C 的实现。C 将向(可能)现有的第一个元素 A 的 vtable 添加虚函数。

A 的基本 vtable

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

派生类 CA 的 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.
+------+

派生类 CB 的 vtable

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

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

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

的大小

关于c++ - 派生类中vtable的理解,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44152605/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com