MST

星途 面试题库

面试题:C++ 多重继承下虚指针的作用机制

在 C++ 的多重继承场景中,一个派生类从多个含有虚函数的基类继承。请详细说明虚指针在此情况下是如何工作的,内存布局是怎样的,以及编译器如何通过虚指针和虚函数表来调用正确的虚函数?
44.2万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

虚指针的工作原理

  1. 概念:虚指针(vptr)是一个指向虚函数表(vtable)的指针。在含有虚函数的类对象中,虚指针通常位于对象内存布局的开头。
  2. 赋值时机:当创建一个派生类对象时,编译器会在构造函数中初始化虚指针,使其指向对应的虚函数表。对于多重继承的派生类,可能会有多个虚指针,分别对应不同基类的虚函数表。

内存布局

  1. 单一基类情况:对于单一基类且含有虚函数的情况,对象内存布局一般为:vptr(指向该基类的虚函数表) + 其他成员变量。
  2. 多重继承情况
    • 派生类从多个含有虚函数的基类继承时,内存布局会相对复杂。通常每个基类的虚指针(如果有)会按照继承顺序排列在对象内存布局的前面,然后是派生类自身的成员变量。
    • 例如,假设有 class Base1 { virtual void func1(); };class Base2 { virtual void func2(); }class Derived : public Base1, public Base2 { /*... */ };,那么 Derived 对象的内存布局可能是:Base1的vptr + Base2的vptr + Derived类成员变量
    • 每个虚函数表(vtable)中存放着对应基类及其派生类中虚函数的地址。如果派生类重写了基类的虚函数,虚函数表中对应的函数地址会被替换为派生类中重写函数的地址。

编译器调用正确虚函数的方式

  1. 通过虚指针找到虚函数表:当通过对象指针或引用调用虚函数时,编译器首先根据对象的类型确定虚指针的位置(因为虚指针位置在对象布局中是固定的)。然后通过虚指针找到对应的虚函数表。
  2. 在虚函数表中查找函数地址:虚函数表中每个条目对应一个虚函数的地址。编译器根据虚函数在虚函数表中的索引(这个索引是在编译期确定的,基于虚函数声明的顺序)找到具体虚函数的地址。
  3. 调用函数:找到虚函数的地址后,编译器生成代码来调用该函数,从而实现动态绑定,确保调用的是运行时对象实际类型所对应的虚函数版本。