MST

星途 面试题库

面试题:C++ 中虚函数表在编译和运行时的关键特性

请简述 C++ 虚函数表在编译阶段和运行时分别是如何生成与维护的?在多重继承的情况下,虚函数表会有怎样的变化?
16.7万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

编译阶段

  1. 生成类的虚函数表
    • 编译器为每个包含虚函数的类创建一个虚函数表(VTable)。
    • 虚函数表是一个指针数组,数组中的每个元素是指向该类虚函数的指针。
    • 编译器按照虚函数在类中声明的顺序,将虚函数的地址依次放入虚函数表中。如果子类重写了父类的虚函数,那么子类虚函数表中对应位置将放置子类重写后的虚函数地址。
  2. 添加虚函数表指针
    • 对于每个包含虚函数的类对象,编译器会在对象的内存布局开头添加一个隐藏的虚函数表指针(vptr)。这个指针指向该类对应的虚函数表。

运行时

  1. 初始化虚函数表指针
    • 在对象构造时,对象的虚函数表指针(vptr)会被初始化,使其指向该对象所属类的虚函数表。这确保了对象能够正确地调用其对应的虚函数。
  2. 多态调用
    • 当通过基类指针或引用调用虚函数时,运行时系统会根据对象实际类型的虚函数表来确定要调用的具体函数。具体过程是,首先通过对象的虚函数表指针找到虚函数表,然后根据虚函数在表中的索引(基于其声明顺序)找到对应的虚函数地址并调用。
  3. 维护:一般情况下,虚函数表在运行时不会动态改变其内容。但是在涉及到一些特殊情况,比如使用dynamic_cast进行类型转换时,运行时系统需要借助虚函数表来进行类型信息的判断等操作,但虚函数表本身内容不变。

多重继承情况

  1. 多个虚函数表
    • 当一个类从多个基类继承,且这些基类中有包含虚函数的类时,该类可能会有多个虚函数表。例如,若类C继承自类A和类B,且AB都有虚函数,那么C可能会有两个虚函数表,一个对应A相关的虚函数(包括C重写自A的虚函数),另一个对应B相关的虚函数(包括C重写自B的虚函数)。
  2. 虚函数表指针
    • 类对象的内存布局中会有多个虚函数表指针,分别指向不同的虚函数表。其顺序与继承列表中基类的顺序相关。
  3. 重写与查找
    • 如果子类重写了某个基类的虚函数,在对应的虚函数表中该虚函数的位置会更新为子类重写后的函数地址。在通过指针或引用调用虚函数时,根据对象实际类型及指针或引用的静态类型来确定从哪个虚函数表中查找要调用的虚函数地址。 例如,若通过A类型的指针调用虚函数,就从与A相关的虚函数表中查找;若通过B类型的指针调用虚函数,就从与B相关的虚函数表中查找。