虚拟表如何存储在内存中?他们的布局?
例如
class A{
public:
virtual void doSomeWork();
};
class B : public A{
public:
virtual void doSomeWork();
};
A 类和 B 类的虚拟表在内存中的布局如何?
对于 Linux 中的 GCC 编译器,请运行:
g++ -fdump-class-hierarchy example.h
输出是:
A 的 Vtable A::_ZTV1A: 3u 条目 0 (int (*)(...))0 8 (int (*)(...))(& _ZTI1A) 16 (int (*)(...))A::doSomeWork A级 大小=8 对齐=8 基本尺寸=8 基本对齐=8 A (0x7fb76785a4e0) 0 几乎为空 vptr=((& A::_ZTV1A) + 16u) B 的 Vtable B::_ZTV1B: 3u 个条目 0 (int (*)(...))0 8 (int (*)(...))(& _ZTI1B) 16 (int (*)(...))B::doSomeWork B类 大小=8 对齐=8 基本尺寸=8 基本对齐=8 B (0x7fb7678510d0) 0 几乎为空 vptr=((& B::_ZTV1B) + 16u) A (0x7fb76785a540) 0 几乎为空 主要用于 B (0x7fb7678510d0)
我还创建了vtable-dumper工具来列出共享对象中虚拟表的内容。使用此工具,您无需编译标头,只需在对象上运行它:
vtable-dumper SHLIB
正如其他人所说,这取决于编译器,而不是您在日常使用 C++ 时真正需要考虑的事情。但是,如果您只是对这个问题感到好奇,您应该阅读 Stan Lippman 的书Inside the C++ Object Model。
内存中的 vtable 布局完全依赖于编译器;没有采取“正确”或普遍的方法。
正如其他人已经写的那样,没有通用的方法。(见鬼,甚至没有人强制要求使用虚拟表。)
但是,我相信它们最有可能实现为对象中某个偏移量处的隐藏指针,该对象引用函数指针表。某些虚函数的地址占据了该表中的某些偏移量。通常还有一个指向动态类型std::type_info
对象的指针。
如果您对此类内容感兴趣,请阅读Lippmann 的“深入 C++ 对象模型”。然而,除非你的兴趣是学术性的(或者你正在尝试编写一个 C++ 编译器——但你不应该问),你不应该打扰。这是一个你不需要知道也不应该依赖的实现细节。
有关Open Watcom类布局的非常详细的描述,请查看Class Layout notes