虚函数表(Vtable)是如何工作的

6

在虚函数表中,当编译器遇到类中的虚函数时,它会创建虚函数表并将虚函数地址放置在其中。继承其他类时也是如此。但是,它是否在每个类中都创建指向每个虚函数表的新指针?如果不是,那么当创建派生类的新实例并分配给基类指针时,如何访问虚函数呢?


可能是Virtual Table C++的重复问题。 - Bo Persson
3个回答

9
每次创建包含虚拟函数的类,或从包含虚拟函数的类派生时,编译器都会为该类创建一个唯一的VTABLE。
如果在基类中声明了一个虚拟函数,但没有覆盖它,则编译器将在派生类中使用基类版本的地址。
然后将VPTR放置到类中。在简单继承中,每个对象只有一个VPTR。必须将VPTR初始化为适当VTABLE的起始地址。(这发生在构造函数中。)
一旦VPTR被初始化为正确的VTABLE,对象实际上“知道”它的类型。但是,除非在调用虚拟函数的点使用自我知识,否则这种自我知识是没有价值的。
当您通过基类地址调用虚拟函数(当编译器没有所有必要的信息来执行早期绑定时的情况)时,会发生特殊的事情。不像执行typical函数调用那样,它只是针对特定地址的汇编语言CALL,而是生成不同的代码来执行函数调用。

所以,你的意思是说。只有一个VPTR在对象创建期间指向特定表,而不是在赋值期间指向特定表。但它将始终存在于基类中。 - Naruto
正如我所说,编译器为一个类及其派生类创建唯一的VTABLE。 - IndieProgrammer
1
关于VTABLE的VPTR怎么样?当您实例化派生类并分配给基础指针时,它是如何工作的? - Naruto
1
当您通过基类指针进行虚函数调用(即进行多态调用)时,编译器会静默插入代码以获取VPTR并在VTABLE中查找函数地址,从而调用正确的函数并导致后期绑定发生。 - IndieProgrammer

5
对于每个带有虚函数的类,都会创建一个虚函数表(vtable)。然后,当使用构造函数创建一个带有vtable的类的对象时,构造函数将适当的vtable复制到对象中。因此,每个对象都有指向其vtable的指针(或在多重继承的情况下,必要时是指向每个vtable的指针)。编译器知道vtable在对象中的位置,因此当需要调用虚方法时,它会输出字节码以确定vtable、查找适当的方法,并跳转到其地址。
在单一继承的简单情况下,子类从父类的vtable开始,并为子类中覆盖父类方法的每个虚方法获取一个被覆盖的条目(对于在子类中不覆盖父类方法的每个虚函数,它还会获得一个新条目)。

3

每当程序编译时,都会创建每个类的虚表,这表明虚表是基于每个类创建的。 在运行时,当对象被创建时,编译器会为对象分配vptr,它指向特定类别对象的虚表。 简而言之,vptr是基于每个对象创建的。


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