面试题答案
一键面试虚函数表指针(vptr)初始化时机
- 普通类对象:
- 当一个类中包含虚函数时,该类的对象会有一个虚函数表指针(vptr)。在对象构造时,vptr 会被初始化。具体来说,在构造函数执行过程中,在进入用户代码之前,编译器会将 vptr 指向该类对应的虚函数表。
- 派生类对象:
- 单继承情况:
- 派生类对象构造时,首先调用基类构造函数。在基类构造函数执行过程中(进入基类构造函数用户代码前),vptr 会被初始化为指向基类的虚函数表。
- 然后执行派生类构造函数,在派生类构造函数执行过程中(进入派生类构造函数用户代码前),vptr 会被重新初始化为指向派生类的虚函数表。如果派生类没有重写基类的虚函数,派生类虚函数表中的对应函数指针仍指向基类虚函数的实现;若派生类重写了虚函数,则虚函数表中对应函数指针指向派生类重写后的函数实现。
- 多继承情况:
- 当派生类从多个基类继承(多继承)且这些基类有虚函数时,派生类对象可能会有多个 vptr(每个有虚函数的基类对应一个 vptr)。
- 构造派生类对象时,按照继承列表顺序依次调用基类构造函数。每个基类构造函数执行时(进入基类构造函数用户代码前),会初始化对应的 vptr 指向该基类的虚函数表。
- 最后执行派生类构造函数,在派生类构造函数执行过程中(进入派生类构造函数用户代码前),会对相关 vptr 进行调整,使其正确指向派生类对应的虚函数表(可能存在覆盖基类虚函数的情况)。如果派生类没有重写某个基类的虚函数,对应虚函数表中的函数指针仍指向基类虚函数的实现;若重写了,则指向派生类重写后的函数实现。
- 菱形继承情况(多继承的一种特殊情况):
- 菱形继承下,若基类有虚函数,派生类对象同样会有多个 vptr 相关情况。构造过程较为复杂,在构造派生类对象时,先构造虚基类子对象,在虚基类构造函数执行过程中(进入虚基类构造函数用户代码前)初始化其对应的 vptr。然后按照继承列表顺序构造其他非虚基类子对象,同样在其构造函数执行过程中(进入非虚基类构造函数用户代码前)初始化对应的 vptr。最后执行派生类构造函数,会对所有 vptr 进行调整,以正确反映派生类的虚函数情况,包括虚函数的重写等。
- 单继承情况: