虚拟函数的Vtable如何工作

How Vtable of Virtual functions work

本文关键字:工作 何工作 函数 Vtable 虚拟      更新时间:2023-10-16

我对Virtual Table有一个小疑问,每当编译器遇到类中的虚函数时,它都会创建Vtable并将虚拟函数地址放在那里。对于继承的其他类,情况类似。它是否在每个类中创建一个指向每个 Vtable 的新指针?如果不是,当创建派生类的新实例并将其分配给基本 PTR 时,它如何访问虚拟函数?

每次创建包含虚函数的类时,或者您派生自包含虚函数的类,编译器为该类创建唯一的 VTABLE。

如果你不要重写在基类中声明为 virtual 的函数,编译器在派生类。

然后,它将 VPTR 放入类。使用简单时,每个对象只有一个 VPTR遗产。必须初始化 VPTR 以指向相应 VTABLE 的起始地址。(这发生在构造函数。将 VPTR 初始化为正确的 VTABLE 后,对象效果"知道"它是什么类型。但这种自我认识是一文不值的除非在调用虚函数时使用它。当您通过基类地址 (编译器没有所有信息的情况执行早期绑定所必需的),发生了一些特殊的事情。而不是执行典型的函数调用,这只是一个汇编语言调用特定地址,编译器生成不同的代码来执行函数调用。

对于每个具有虚函数的类,将创建一个 vtable。然后,当使用构造函数创建具有可行类的对象时,构造函数会将相应的 vtable 复制到该对象中。 因此,每个对象都有一个指向其 vtable 的指针(或者,在多重继承的情况下,必要时,指向其每个 vtable 的 Orr)。编译器知道 vtable 在对象中的位置,因此当它需要调用虚拟方法时,它会输出字节码以阻止 vtable,查找适当的方法,并跳转到其地址。

在单一继承的简单情况下,子类从父类的 vtable 的副本开始,然后为子类中的每个虚拟方法获取重写的条目,该条目覆盖父类的方法。(并且它还为子包覆中的每个虚拟函数获取一个新条目,该条目不会覆盖父类方法)

每当程序编译时,都会为每个类创建虚拟表,这清楚地表明了 vtables 是按类创建的。在运行时,当创建对象时,编译器将 vptr 分配给该对象,该对象指向特定类对象的虚拟表。简而言之,vptr 是按对象创建的。