虚拟方法表在C++中存储在哪里
Where does virtual method table store in C++?
我想知道类对象(不是实例,而是类)是如何存储在内存中的?
class A {
public:
int a;
virtual void f();
virtual ~A();
};
class B : public A {
public:
int b;
void f() final override;
};
我知道,在这种继承(B源自A)的情况下,通常(标准中没有强烈描述)我们有:
memory: ....AB...
其中AB是B的类对象(如果我理解正确的话)。如果我们更深入(尝试使用clang和gcc),我们可以看到类似的东西(同样,在标准中没有强烈描述):
A
vtptr*
int a
B
vtptr*
int b
好的,现在我们看看a
和b
属性存储在哪里。我们还看到了指向虚拟方法表的指针。但是vtptr*
(虚拟方法表)实际存储在哪里?为什么不去上课呢?还是真的?
此外,还有一个问题:我能够通过更改指针(简单逻辑)来更改虚拟方法表。我还可以安全地更改指向其方法的指针吗?
附言:在你的问题中,你可以回答gcc和clang。附言:如果我哪里错了,请在你的答案中也指出。
C++标准没有规定虚拟函数机制应该如何实现。在实践中,所有C++实现都为每个类使用一个虚拟函数表,并在具有虚拟函数的类(称为多态类)的每个对象中使用虚拟函数表指针。然而,细节可能会有所不同,特别是对于多重继承和虚拟继承。
您可以在Stanley Lippman的经典著作《C++对象模型内幕》中了解常见的选择。
问";其中;存储虚拟功能表。它很像任何静态变量:它的位置取决于实现,并且几乎是任意的。关于
"为什么不去上课呢?
…类本身没有存储在任何地方,它们不是对象,所以这没有意义,对不起。
对于给定的实现,您可以更有意义地问每个对象中存储的vtable指针在哪里?
通常是在对象的开头,但如果你从一个非多态类派生,并添加一个虚拟函数,那么你可能会在其他地方获得vtable指针。或者不是。后一种可能性是Derived*
到Base*
的static_cast
(反之亦然)可以进行地址调整的主要原因,即不同于简单的reinterpret_cast
。
阅读关于虚拟方法表的wiki页面。
存储的vtable(本身)在哪里是特定于实现的(编译器、链接器、操作系统特定)。但它通常存储在可执行文件的代码段中(就像文字字符串一样)。因此,对象通常(即没有多重继承)以指向其vtable的_vptr
指针开始。使用多个或虚拟继承,您可以拥有多个vtable指针。
正如所评论的,你不应该关心这些细节。如果您真的很关心,请让编译器转储内部表示或发出的程序集代码。(例如使用g++ -fdump-tree-all -fverbose-asm -S
编译)
但是vtptr*(虚拟方法表)实际上在哪里[点]?为什么不去上课呢?还是真的?
它可能在任何地方。。。谁在乎呢?它的工作方式通常是这样的。。。假设class A
:有一个隐藏的static
成员
VDT A::vdt = {
{ address of A::f code,
address of A::~A code },
miscellaneous type-specific information needed for dynamic cast etc.
};
确切的布局是未知的,但很可能存在virtual
成员函数的地址数组。与任何static
信息一样,地址与任何给定对象实例的地址无关。。。对象中指向虚拟调度表的指针允许这种解耦。
此外,还有一个问题:我能够通过更改指针(简单逻辑)来更改虚拟方法表。我还可以安全地更改指向其方法的指针吗?
这是不安全的,即使它表面上有效,有时也可能不会得到一致的遵守(例如,在编译器能够在编译时确定要调用的特定覆盖的情况下,它可能会完全绕过运行时虚拟调度表咨询)。
- 谷歌测试中的期望值存储在哪里
- 常量参数存储在哪里 (C++)?
- 此递归函数的每次迭代的值存储在哪里?
- 如何告诉本机节点模块所需的dll存储在哪里?
- 模板参数在 C++ 中存储在哪里?
- C++ - thread_local变量存储在哪里?
- 返回值存储在哪里?
- glVertexAttribDivisor 存储在哪里 - VAO、VBO 或全局状态?
- 虚拟函数在哪里使用 vpointer to vtable 来解析方法调用,非虚拟方法存储在哪里以及如何解析它们?
- 为什么类型转换对象不会更改其地址?有关对象类型的信息存储在哪里?
- C++ - 函数中的局部指针变量具有什么类型的存储持续时间以及它们存储在哪里?
- bazel 项目将其".so"文件存储在哪里?
- 返回对象存储在哪里
- OpenSSL dll文件存储在哪里
- 如果我在我的函数中返回一个类,它存储在哪里
- 变量名称存储在哪里
- 引用变量存储在哪里
- 数组的指针,该数组的每个元素的内存空间信息存储在哪里
- 常量数据存储在哪里
- 编译时局部变量存储在哪里