Vptr中的疑惑 - 想知道它如何获取Vtable地址

3

我想知道vptr如何获取vtable基地址。

例如

class A
{
virtual getdata();
int a;
}

现在,

A obj; /// here vptr getting vtable's base address.

我想知道这个谜题的答案...提前感谢。

你在问编译器如何知道虚函数表的地址? - Yuval Adam
你的编译器甚至可能不使用虚函数表。C++标准中没有要求使用虚函数表。 - Martin York
4个回答

1

vptr 是由编译器生成的代码在初始化 obj 的过程中进行初始化的。这里没有什么魔法,它只是像这样分配:

struct __A_vtbl_def {
    void (*getdata)(__A*);
};

__A_vtbl_def __A_vtbl = {
    &A__getdata
};

struct __A {
    __A_vtbl_def* vptr;
    int a;
};

__A obj;
obj.vptr = &__A_vtbl;

注意:这只是虚构的代码,展示了编译器如何实现vptr。我不知道现在编译器会生成什么样的实际代码。

1

A 的构造函数将自动初始化 vtable 指针,使其指向正确的 vtable。以下是我的编译器为您的特定示例生成的汇编代码片段(来自 A::A):

004114A3  mov         eax,dword ptr [this] 
004114A6  mov         dword ptr [eax],offset A::`vftable' (415740h) 

正如你所见,编译器生成的代码将类A的虚函数表指针复制到实例的开头。


+1 是指出这通常是添加到构造函数的代码。它实际上展示了如何将vtable _pointer_复制到对象中。 (“offset A :: vftable”=内存中的偏移量=指针) - MSalters

1

这不是关于C++的问题,C++中没有vtable或vptr,一些供应商使用vtable实现虚函数,但这完全取决于实现。


1
虽然实际上“所有”编译器都使用vtable,所以我认为这个问题是完全合法的。 - Andreas Brinck
1
嗯,有一个关于_vtable的假设。虽然可能,但大多数编译器无法将所有虚函数放在单个表中。因此,许多编译器为复杂类型生成多个vtable。此时真正的问题出现了:运行时如何选择正确的vtable? - MSalters
@MSalters,您真的知道有一个编译器可以做到这一点吗?如果是这样,它们在运行时如何解决这个问题? - Andreas Brinck
@MSalters 好的,我想了一下,得出结论应该是可行的。你可以基本上有一个vtable的"vtable"或类似的东西。 - Andreas Brinck
据我所知,MSVC和GCC都会在对象内部的不同偏移处分散多个vptr,并在转换后调整对象指针。在这种情况下,指向虚成员函数的指针变得非常复杂,你可以想象一下。 - MSalters

0
编译器会生成一个类的虚函数表,而虚函数表的地址在编译时就已经确定。因此,如果你在运行时实例化一个对象,那么 vptr 将获取虚函数表的地址。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接