MST

星途 面试题库

面试题:C++ 多态对象在内存中的存储方式及原理

在C++中,多态是如何实现的?从内存存储的角度详细阐述包含虚函数的类对象在内存中的布局,以及在运行时如何根据对象类型正确调用虚函数。
43.7万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

多态的实现方式

在C++ 中,多态主要通过虚函数(virtual function)和指针或引用(pointer or reference)来实现。

  1. 编译时多态:通过函数重载(function overloading)和模板(template)实现。函数重载是指在同一作用域内,可以有多个同名函数,但参数列表不同。模板则允许编写通用的代码,根据实际使用的类型生成具体的代码。

  2. 运行时多态:通过虚函数和指针或引用实现。当一个基类指针或引用指向派生类对象时,根据对象的实际类型来决定调用哪个类的虚函数。

包含虚函数的类对象内存布局

当一个类包含虚函数时,该类对象在内存中的布局如下:

  1. 虚函数表指针(vptr):位于对象内存布局的起始位置,该指针指向一个虚函数表(vtable)。虚函数表是一个存储虚函数地址的数组。
  2. 数据成员:对象的数据成员紧跟在虚函数表指针之后存储,按照声明顺序排列。

例如,假设有如下类定义:

class Base {
public:
    virtual void func() {}
    int data;
};

Base类对象在内存中的布局大致如下:

+----------------+
| vptr           |
+----------------+
| data           |
+----------------+

运行时虚函数调用过程

  1. 对象创建:当创建一个包含虚函数的类对象时,编译器会在对象的起始位置插入一个虚函数表指针(vptr),并初始化该指针指向对应的虚函数表(vtable)。对于派生类对象,vptr指向派生类的虚函数表。如果派生类重写了基类的虚函数,虚函数表中对应位置会存储派生类虚函数的地址;否则,存储基类虚函数的地址。
  2. 虚函数调用:当通过基类指针或引用调用虚函数时,运行时系统首先根据对象的虚函数表指针找到对应的虚函数表。然后,根据虚函数在虚函数表中的索引,找到实际要调用的虚函数的地址,并执行该函数。

例如:

Base* ptr = new Derived();
ptr->func();

在上述代码中,ptr是一个指向Derived对象的Base类指针。当调用ptr->func()时,运行时系统首先通过ptr找到Derived对象的虚函数表指针,然后根据虚函数表中func的索引找到Derived::func的地址,并调用该函数。这样就实现了根据对象的实际类型正确调用虚函数,从而实现运行时多态。