MST

星途 面试题库

面试题:多重继承下C++虚函数的底层实现

在C++多重继承场景下,虚函数的底层实现会变得更为复杂。请阐述在一个类继承自多个包含虚函数的基类时,虚函数表的布局和调用机制是怎样的。通过编写一段多重继承的代码,并分析其虚函数表相关的内存布局来展示你的理解。
26.3万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

虚函数表布局和调用机制

在C++多重继承中,当一个类继承自多个包含虚函数的基类时:

  1. 虚函数表布局:每个基类会有自己的虚函数表(vtable)。派生类对象的内存布局中,会为每个基类的虚函数表分配空间。这些虚函数表按继承顺序排列,每个虚函数表中存储着对应基类虚函数的地址。
  2. 调用机制:当通过派生类对象指针或引用调用虚函数时,编译器根据对象的内存布局找到对应的虚函数表,然后在虚函数表中找到对应的虚函数地址并调用。

代码示例

#include <iostream>

class Base1 {
public:
    virtual void func1() { std::cout << "Base1::func1" << std::endl; }
};

class Base2 {
public:
    virtual void func2() { std::cout << "Base2::func2" << std::endl; }
};

class Derived : public Base1, public Base2 {
public:
    void func1() override { std::cout << "Derived::func1" << std::endl; }
    void func2() override { std::cout << "Derived::func2" << std::endl; }
};

内存布局分析

  1. 使用工具:在GCC下,可以使用objdump -d -S命令反汇编可执行文件来查看虚函数表相关信息。
  2. 内存布局
    • Derived对象的内存布局首先是Base1的部分,其中包含指向Base1虚函数表的指针(vptr),这个虚函数表中func1的地址是Derived::func1的地址(因为Derived重写了func1)。
    • 接着是Base2的部分,包含指向Base2虚函数表的指针,此虚函数表中func2的地址是Derived::func2的地址(因为Derived重写了func2)。
    • 例如,当通过Derived对象指针调用func1时,会先找到Base1虚函数表指针,再在Base1虚函数表中找到func1的地址并调用Derived::func1。调用func2类似,通过Base2虚函数表指针找到func2地址调用Derived::func2