5

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

4

3 回答 3

7

每次创建包含虚函数的类或从包含虚函数的类派生时,编译器都会为该类创建一个唯一的 VTABLE。

如果您不覆盖在基类中声明为 virtual 的函数,编译器将使用派生类中基类版本的地址。

然后它将 VPTR 放入类中。使用简单继承时,每个对象只有一个 VPTR。必须将 VPTR 初始化为指向相应 VTABLE 的起始地址。(这发生在构造函数中。)一旦将 VPTR 初始化为正确的 VTABLE,对象实际上“知道”它是什么类型。但是,除非在调用虚函数时使用它,否则这种自知是毫无价值的。当您通过基类地址调用虚函数时(编译器没有执行早期绑定所需的所有信息的情况),会发生一些特殊情况。编译器不执行典型的函数调用,即简单地对特定地址进行汇编语言调用,而是生成不同的代码来执行函数调用。

于 2012-04-08T18:20:01.687 回答
4

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

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

于 2012-04-08T18:17:10.797 回答
3

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

于 2012-09-03T12:24:46.913 回答