MST

星途 面试题库

面试题:C++ 虚函数表与多重继承下的存储位置复杂性

假设存在一个C++类体系,其中有一个基类Base带有虚函数,然后有一个派生类Derived1继承自Base,还有另一个派生类Derived2也继承自Base。现在有一个类MultipleDerived同时继承自Derived1和Derived2。请详细分析MultipleDerived类对象的内存布局中虚函数表的存储位置,以及在调用不同虚函数时如何通过虚函数表找到对应的函数地址,同时说明可能出现的菱形继承问题与虚函数表存储的关系。
40.1万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

MultipleDerived类对象内存布局中虚函数表的存储位置

  1. 虚函数表指针:在C++中,当一个类包含虚函数时,该类对象会包含一个指向虚函数表(vtable)的指针(vptr)。对于MultipleDerived类,由于它继承自Derived1Derived2,而Derived1Derived2又继承自带有虚函数的Base类,所以MultipleDerived类对象会包含多个虚函数表指针。具体来说,它会有至少两个虚函数表指针,分别对应从Derived1Derived2继承而来的虚函数表。
  2. 存储位置:通常,这些虚函数表指针存储在MultipleDerived类对象内存布局的起始位置(具体位置依赖于编译器实现)。每个虚函数表指针指向一个特定的虚函数表,这些虚函数表存储了该类及其基类虚函数的地址。

通过虚函数表找到对应函数地址的过程

  1. 调用虚函数:当通过MultipleDerived类对象调用虚函数时,首先根据对象类型确定要使用的虚函数表指针。例如,如果调用的虚函数是从Derived1继承而来的,就使用对应Derived1的虚函数表指针。
  2. 查找虚函数表:找到对应的虚函数表指针后,通过该指针访问虚函数表。虚函数表是一个函数指针数组,每个元素存储一个虚函数的地址。
  3. 确定函数地址:在虚函数表中,根据虚函数在表中的索引找到对应的函数地址。这个索引是在编译时确定的,不同的虚函数有不同的索引值。找到函数地址后,就可以调用相应的虚函数。

菱形继承问题与虚函数表存储的关系

  1. 菱形继承问题:在上述继承体系中,如果Base类被Derived1Derived2继承,MultipleDerived又继承自Derived1Derived2,就形成了菱形继承。菱形继承会导致MultipleDerived类对象中存在Base类成员的两份拷贝,这不仅浪费内存,还可能导致访问歧义。
  2. 虚函数表存储影响:由于存在两份Base类子对象,在虚函数表存储方面,每个Base类子对象对应的虚函数表可能会有重复的虚函数条目(如果虚函数没有被重新定义)。这增加了虚函数表的大小,并且在调用虚函数时,需要明确指定从哪个Base类子对象的虚函数表中查找函数地址,否则可能出现歧义。
  3. 解决方法 - 虚继承:为了解决菱形继承问题,可以使用虚继承。在Derived1Derived2继承Base类时使用虚继承(例如class Derived1 : virtual public Base),这样MultipleDerived类对象中只会有一份Base类子对象。在虚继承情况下,虚函数表的结构会更复杂,可能会引入额外的指针来处理虚基类子对象的偏移等信息,但能有效避免菱形继承带来的重复成员和访问歧义问题。