当前位置: 首页 > article >正文

C++虚函数与类对象模型深度解析

目录

1. 引言

2. 单继承下的虚函数表

2.1 基本概念

2.2 示例分析

3. 多重继承下的虚函数表

3.1 基本概念

3.2 示例分析

4. 虚函数表指针(vptr)的存储

4.1 单继承

4.2 多重继承

5. 常见面试题解析

问题1:D 继承 B1 和 B2,D 新增虚函数放在哪里?

问题2:D 有几个虚表指针?

问题3:如果 B1 没有虚函数,B2 有虚函数

6. 总结


1. 引言

在C++中,虚函数是实现运行时多态(动态绑定)的核心机制,而虚函数表(vtable)和虚表指针(vptr)是实现这一机制的关键。理解虚函数在类对象模型中的存储方式,对于深入掌握C++面向对象编程至关重要。本文将详细分析:

  • 单继承下的虚函数表布局
  • 多重继承下的虚函数表布局
  • 虚函数表指针(vptr)的存储方式
  • 新增虚函数对虚表的影响

2. 单继承下的虚函数表

2.1 基本概念

当一个类包含虚函数时,编译器会为该类生成一个虚函数表(vtable),存储所有虚函数的地址。每个对象的内存布局中,前4字节(32位系统)或前8字节(64位系统)存储指向虚函数表的指针(vptr)。

2.2 示例分析

class A {
public:virtual void func1() { cout << "A::func1" << endl; }virtual void func2() { cout << "A::func2" << endl; }
};class B : public A {
public:virtual void func1() override { cout << "B::func1" << endl; } // 重写virtual void func3() { cout << "B::func3" << endl; }          // 新增
};

内存布局:

对象虚表指针(vptr)虚表内容
Avptr_AA::func1A::func2
Bvptr_BB::func1(重写), A::func2B::func3(新增)

关键点:

  • B 继承 A,因此 B 的虚表包含 A 的所有虚函数(func1 被重写,func2 保留)。
  • B 新增的 func3 附加到虚表末尾。

3. 多重继承下的虚函数表

3.1 基本概念

在多重继承中,派生类会为每个包含虚函数的基类维护一个独立的虚函数表。如果派生类新增虚函数,它们会附加到第一个基类的虚表末尾

3.2 示例分析

class B1 {
public:virtual void f1() { cout << "B1::f1" << endl; }
};class B2 {
public:virtual void f2() { cout << "B2::f2" << endl; }
};class D : public B1, public B2 {
public:virtual void f1() override { cout << "D::f1" << endl; }  // 重写 B1::f1virtual void f2() override { cout << "D::f2" << endl; }  // 重写 B2::f2virtual void f3() { cout << "D::f3" << endl; }           // 新增虚函数
};

内存布局:

对象虚表指针(vptr)虚表内容
Dvptr_B1D::f1D::f3(新增)
vptr_B2D::f2

关键点:

  • D 继承 B1 和 B2,因此有 2 个虚表指针vptr_B1 和 vptr_B2)。
  • D 新增的 f3 附加到 B1 的虚表末尾(因为 B1 是第一个基类)。
  • B2 的虚表仅存储 D 重写的 f2

4. 虚函数表指针(vptr)的存储

4.1 单继承

  • 只有一个 vptr,位于对象起始地址。
  • 示例:
A a;
B b;
cout << *(void**)&a; // 输出 A 的虚表地址
cout << *(void**)&b; // 输出 B 的虚表地址

4.2 多重继承

  • 每个基类对应一个 vptr,按继承顺序排列。
  • 示例:
D d;
void** vptr1 = *(void***)&d;                     // B1 的 vptr
void** vptr2 = *(void***)((char*)&d + sizeof(B1)); // B2 的 vptr

5. 常见面试题解析

问题1:D 继承 B1 和 B2D 新增虚函数放在哪里?

答案:放在第一个基类 B1 的虚表末尾。

问题2:D 有几个虚表指针?

答案:2 个(对应 B1B2)。

问题3:如果 B1 没有虚函数,B2 有虚函数

6. 总结

继承方式虚表指针数量新增虚函数存储位置
单继承1附加到基类虚表末尾
多重继承等于基类数量附加到第一个基类虚表末尾

关键结论:

  1. 虚函数表(vtable)是实现动态绑定的核心。
  2. 单继承时,派生类虚表包含基类虚函数 + 新增虚函数。
  3. 多重继承时,派生类为每个基类维护独立虚表,新增虚函数放在第一个基类虚表末尾。
http://www.lryc.cn/news/2386140.html

相关文章:

  • 3d世界坐标系转屏幕坐标系
  • 【2025】基于Springboot + vue + 协同过滤算法实现的旅游推荐系统
  • AI数据治理破局的战略重构
  • QT6安装与概念介绍
  • Python包管理工具uv 国内源配置
  • ABP VNext + Webhook:订阅与异步回调
  • Docker(二):开机自启动与基础配置、镜像加速器优化与疑难排查指南
  • Lua基础语法
  • 2025年渗透测试面试题总结-匿名[实习]安全工程师(安全厂商)(题目+回答)
  • 【node.js】实战项目
  • 从AD9361 到 ADSY1100 ,中间的迭代产品历史
  • 免费插件集-illustrator插件-Ai插件-查找选中颜色与pantone中匹配颜色
  • redis集合类型
  • [爬虫实战] 爬微博图片:xpath的具体运用
  • MySQL中简单的操作
  • NNG和DDS
  • 防震基座在半导体晶圆制造设备抛光机详细应用案例-江苏泊苏系统集成有限公司
  • 框架开发与原生开发的权衡:React案例分析(原生JavaScript)
  • Lua5.4.2常用API整理记录
  • Python打卡训练营学习记录Day36
  • ### Mac电脑推送文件至Gitee仓库步骤详解
  • 官方SDK停更后的选择:开源维护的Bugly Unity SDK
  • 什么是智能体agent?
  • 【多线程】Java 实现方式及其优缺点
  • Obsidian 数据可视化深度实践:用 DataviewJS 与 Charts 插件构建智能日报系统
  • Three.js 海量模型加载性能优化指南
  • 6.4.3_有向无环图描述表达式
  • 力扣第157场双周赛
  • 青少年编程与数学 02-019 Rust 编程基础 19课题、项目发布
  • 【HarmonyOS Next之旅】DevEco Studio使用指南(二十五) -> 端云一体化开发 -> 业务介绍(二)