我对虚拟表有一点疑问,每当编译器遇到类中的虚函数时,它就会创建Vtable并在那里放置虚函数地址。对于继承的其他类,它也会发生类似的情况。它是否在每个类中创建一个指向每个Vtable的新指针?如果不是,当创建派生类的新实例并将其分配给Base PTR时,它如何访问虚函数?
答案 0 :(得分:6)
每次创建包含虚拟功能的类时,或者您 派生自包含虚函数的类,即编译器 为该类创建一个唯一的VTABLE。
如果你 不要覆盖在基类中声明为虚拟的函数, 编译器使用的是基类版本的地址 衍生类。
然后它将VPTR放入 班级。使用简单时,每个对象只有一个VPTR 继承。必须初始化VPTR以指向 相应VTABLE的起始地址。 (这发生在 构造函数)。 一旦VPTR初始化为适当的VTABLE,对象就在 效果“知道”它是什么类型。但这种自我认识毫无价值 除非在调用虚函数时使用它。 通过基类地址调用虚函数时( 编译器没有所有信息时的情况 有必要进行早期绑定),会发生一些特殊情况。 而不是执行典型的函数调用,这只是一个 汇编语言CALL到特定地址,编译器 生成不同的代码来执行函数调用。
答案 1 :(得分:4)
对于具有虚函数的每个类,都会创建一个vtable。然后,当使用构造函数创建具有可行的类的对象时,构造函数将相应的vtable复制到对象中。因此,每个对象都有一个指向其vtable的指针(或者在多重继承的情况下,必要时,每个对象都有一个Orr)。编译器知道vtable在对象中的位置,因此当需要调用虚方法时,它会输出字节代码以威慑vtable,查找适当的方法,并跳转到其地址。
在单继承的简单情况下,子类以父类的vtable的副本开始,然后为子类中的每个虚方法获取一个重写的条目,该方法将覆盖父类的方法。 (并且它还为子层中的每个虚拟函数获取一个新条目, not 覆盖父类方法)
答案 2 :(得分:3)
每当程序编译每个类的虚拟表时都会创建,这清楚地表明vtable是按类创建的。 在运行时,创建对象时,编译器会将vptr分配给对象,该对象指向特定类对象的虚拟表。 简而言之,vptr是基于每个对象创建的。