ren*_*nzo 6 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();
};
Run Code Online (Sandbox Code Playgroud)
在86的情况下和对齐= 4,A并且B在存储器中看起来像这样:
+------+------+
A: | vptr | a |
+------+------+
sizeof(A) = 4 + 4 = 8
+------+------+------+------+
B: | vptr | b |
+------+------+------+------+
sizeof(B) = 8 + 8 = 16
Run Code Online (Sandbox Code Playgroud)
但是当我尝试重新组装时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
Run Code Online (Sandbox Code Playgroud)
那么vptr在C哪里?我可以假设编译器合并了不同的虚拟表(例如A和的vptr C),但在这种情况下为什么sizeof(C)返回sizeof(A)+ sizeof(B)+ sizeof(alligned_char)+ sizeof(vptr)
在struct D : public C {}具有相同的故事-不存在的vptr D.
我使用的编译器是msvc 2012 x86.
编译器必须兼顾简单性和基类需要存在于对象中的事实。
+------+---------+----+
| A | B | C |
+------+---------+----+
Run Code Online (Sandbox Code Playgroud)
所以
A 和 B 中的虚函数将针对派生类 C 的实现进行修补。C 将向(可能)现有的第一个元素添加虚函数A的 vtable 中。
A 的基础虚函数表
+------+
| A:fa |
+------+
Run Code Online (Sandbox Code Playgroud)
A派生类中的 vtableC
+------+
| 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.
+------+
Run Code Online (Sandbox Code Playgroud)
B派生类中的 vtableC
+------+
| C:fb | // overridden, but no need to add fc, fa to this table.
+------+
Run Code Online (Sandbox Code Playgroud)
我认为对齐规则导致 的大小被C填充,以便对齐敏感的双精度数正确对齐(确保数组C正确对齐)。
的大小B是 (4) 的大小vptr和填充,以确保(4) 和(8)double的大小对齐double