MST

星途 面试题库

面试题:C++对象模型与内存布局

假设我们有一个继承体系,基类A包含一个虚函数,派生类B继承自A并覆盖了该虚函数,同时B还包含一些成员变量。请详细描述这个继承体系下对象的内存布局是怎样的?并且说明编译器是如何管理虚函数表指针和成员变量内存分布的?
41.5万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试
  1. 对象的内存布局
    • 基类A
      • 当类A中有虚函数时,其对象在内存中首先包含一个虚函数表指针(vptr),用于指向虚函数表。虚函数表是一个存储类中虚函数地址的数组。之后是类A本身定义的成员变量(如果有的话)。
    • 派生类B
      • 派生类B的对象内存布局,首先是基类A的部分,即虚函数表指针(vptr)和基类A的成员变量(按照基类A中的布局顺序)。这部分是因为B继承自A,所以要包含A的所有非静态成员。
      • 接着是派生类B自己定义的成员变量,按照在B类中声明的顺序排列。
  2. 编译器对虚函数表指针和成员变量内存分布的管理
    • 虚函数表指针
      • 编译器在生成类的对象布局时,会为每个包含虚函数的类(包括基类A和派生类B)创建一个虚函数表。
      • 当创建对象时,编译器会在对象内存布局的起始位置放置虚函数表指针,使其指向对应的虚函数表。对于派生类B,编译器会根据B对虚函数的覆盖情况来填充虚函数表。如果B覆盖了基类A的虚函数,那么虚函数表中对应的虚函数地址就是B中覆盖后的函数地址;如果B没有覆盖某个虚函数,虚函数表中该函数地址仍然是基类A中虚函数的地址。
    • 成员变量内存分布
      • 对于基类A的成员变量,编译器按照它们在A类中声明的顺序,在虚函数表指针之后分配内存空间。
      • 对于派生类B自己的成员变量,编译器在基类A部分(虚函数表指针和基类成员变量)之后,按照B类中声明的顺序分配内存空间。编译器通过这种固定的布局方式,使得程序在运行时能够准确地访问对象的成员变量和虚函数。