面试题答案
一键面试编译阶段
- 生成类的虚函数表:
- 编译器为每个包含虚函数的类创建一个虚函数表(VTable)。
- 虚函数表是一个指针数组,数组中的每个元素是指向该类虚函数的指针。
- 编译器按照虚函数在类中声明的顺序,将虚函数的地址依次放入虚函数表中。如果子类重写了父类的虚函数,那么子类虚函数表中对应位置将放置子类重写后的虚函数地址。
- 添加虚函数表指针:
- 对于每个包含虚函数的类对象,编译器会在对象的内存布局开头添加一个隐藏的虚函数表指针(vptr)。这个指针指向该类对应的虚函数表。
运行时
- 初始化虚函数表指针:
- 在对象构造时,对象的虚函数表指针(vptr)会被初始化,使其指向该对象所属类的虚函数表。这确保了对象能够正确地调用其对应的虚函数。
- 多态调用:
- 当通过基类指针或引用调用虚函数时,运行时系统会根据对象实际类型的虚函数表来确定要调用的具体函数。具体过程是,首先通过对象的虚函数表指针找到虚函数表,然后根据虚函数在表中的索引(基于其声明顺序)找到对应的虚函数地址并调用。
- 维护:一般情况下,虚函数表在运行时不会动态改变其内容。但是在涉及到一些特殊情况,比如使用
dynamic_cast
进行类型转换时,运行时系统需要借助虚函数表来进行类型信息的判断等操作,但虚函数表本身内容不变。
多重继承情况
- 多个虚函数表:
- 当一个类从多个基类继承,且这些基类中有包含虚函数的类时,该类可能会有多个虚函数表。例如,若类
C
继承自类A
和类B
,且A
和B
都有虚函数,那么C
可能会有两个虚函数表,一个对应A
相关的虚函数(包括C
重写自A
的虚函数),另一个对应B
相关的虚函数(包括C
重写自B
的虚函数)。
- 当一个类从多个基类继承,且这些基类中有包含虚函数的类时,该类可能会有多个虚函数表。例如,若类
- 虚函数表指针:
- 类对象的内存布局中会有多个虚函数表指针,分别指向不同的虚函数表。其顺序与继承列表中基类的顺序相关。
- 重写与查找:
- 如果子类重写了某个基类的虚函数,在对应的虚函数表中该虚函数的位置会更新为子类重写后的函数地址。在通过指针或引用调用虚函数时,根据对象实际类型及指针或引用的静态类型来确定从哪个虚函数表中查找要调用的虚函数地址。 例如,若通过
A
类型的指针调用虚函数,就从与A
相关的虚函数表中查找;若通过B
类型的指针调用虚函数,就从与B
相关的虚函数表中查找。
- 如果子类重写了某个基类的虚函数,在对应的虚函数表中该虚函数的位置会更新为子类重写后的函数地址。在通过指针或引用调用虚函数时,根据对象实际类型及指针或引用的静态类型来确定从哪个虚函数表中查找要调用的虚函数地址。 例如,若通过