MST

星途 面试题库

面试题:C++虚函数表输出在多重继承场景下的解析

在C++的多重继承体系中,假设基类A和B都有虚函数,类C同时继承自A和B,且覆盖了部分虚函数。请详细说明C类对象的虚函数表结构是怎样的,以及如何从虚函数表输出内容来分析函数调用过程,尤其是涉及到菱形继承的情况。
42.8万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

C类对象的虚函数表结构

  1. 一般多重继承情况
    • 由于C类同时继承自A和B,C类对象会有两个虚函数表指针(假设编译器采用这种布局方式),分别对应基类A和基类B的虚函数表。
    • 虚函数表中,对于C类覆盖的虚函数,会在虚函数表中相应位置替换为C类的函数指针。未覆盖的虚函数,依然保留基类的函数指针。例如,如果C类覆盖了A类的virtual void funcA(),那么对应A类虚函数表中funcA的位置,存储的是C类funcA的函数指针;若C类没有覆盖B类的virtual void funcB(),B类虚函数表中funcB的位置,存储的是B类funcB的函数指针。
  2. 菱形继承情况
    • 假设存在菱形继承结构,D类从C类(C类多重继承自A和B)公有继承。在这种情况下,C类的虚函数表结构基本不变,但D类会有更复杂的情况。
    • 如果D类覆盖了一些虚函数,这些虚函数的函数指针会替换到相应虚函数表(A或B对应的虚函数表)中的位置。同时,由于菱形继承可能会导致虚基类的引入(为了避免数据冗余),虚函数表可能会增加一些与虚基类相关的调整信息,例如用于定位虚基类子对象的偏移量等。

从虚函数表输出内容分析函数调用过程

  1. 一般多重继承
    • 当调用C类对象的虚函数时,例如c.funcA()(假设funcA是A类的虚函数且C类覆盖了它),首先通过C类对象的第一个虚函数表指针(对应A类虚函数表)找到A类虚函数表。
    • 在虚函数表中,根据funcA在虚函数表中的索引位置,获取到C类funcA的函数指针。
    • 然后通过该函数指针调用C类的funcA函数。
  2. 菱形继承
    • 对于D类对象调用虚函数,例如d.funcA()(假设funcA是A类的虚函数且经过多重继承和覆盖)。
    • 首先根据D类对象的虚函数表指针(对应A类虚函数表方向)找到虚函数表。
    • 虚函数表中可能会有一些额外信息用于处理虚基类相关的调整。如果funcA被D类覆盖,虚函数表中相应位置存储的是D类funcA的函数指针,通过该指针调用D类的funcA;如果未被D类覆盖但被C类覆盖,则找到C类funcA的函数指针并调用C类的funcA。如果都未覆盖,则找到A类funcA的函数指针调用A类的funcA。同时,虚函数表中的额外信息会协助处理虚基类相关的地址调整,以确保在复杂继承结构下能够正确定位函数和相关对象数据。