深入C++之:一个类有几张虚函数表?

1. 没有任何虚函数的类:0 张

如果一个类没有声明任何虚函数,且它的所有基类也没有虚函数,那么编译器不会为这个类生成虚函数表。该类的对象内存中也不存在虚指针(vptr),完全是纯粹的数据成员集合。

2. 包含虚函数的基类 / 单继承:1 张

只要类中出现了虚函数,或者它通过单继承 自一个带有虚函数的基类,那么这个类就只有 1 张虚函数表。

  • 普通基类:编译器会为其生成 1 张虚表,存储所有虚函数的地址。该类的对象内部会悄悄插入 1 个虚指针(vptr)指向这张表。

  • 单重派生类:派生类会"拷贝"基类的虚表结构。

    • 如果派生类重写(override)了基类的虚函数,虚表中对应的函数地址会被替换为派生类自己的版本。

    • 如果派生类新增了独有的虚函数,这些函数的地址会被直接追加到这 1 张虚表的末尾。

3. 多重继承:多张(取决于有虚函数的基类数量)

在多重继承中,一个类会拥有多张 虚函数表。具体数量通常等于包含虚函数的基类的个数

假设类 Derived 继承自 Base1Base2(两者都有虚函数):

  • Derived 会拥有 2 张 虚函数表(分别对应 Base1 的子对象和 Base2 的子对象)。

  • Derived 实例化出的对象内存中,会包含 2 个虚指针(vptr),分别指向这 2 张不同的虚表。

  • 注意 :如果 Derived 自己新增了虚函数,按照主流编译器(如 GCC 和 MSVC)的实现,这些新增的虚函数地址通常会被追加到**第一个基类(Base1)**的虚函数表末尾,而不会去创建第 3 张表。

4. 虚继承(如菱形继承):情况复杂,包含 vbtable

当使用 virtual 关键字进行继承(为了解决多重继承带来的数据冗余问题)时,底层模型会发生本质变化:

  • 编译器会引入一种新的表:虚基类表(Virtual Base Table, vbtable),对象内部会增加指向该表的指针(vbptr),用于在运行时定位共享的虚基类子对象的位置。

  • 关于虚函数表(vtable)的数量:如果基类有虚函数,它依然有自己的虚表。但如果派生类在虚继承的同时又新增了虚函数,某些编译器(如 MSVC)为了内存对齐和安全,可能会为派生类额外单独生成 1 张新的虚函数表。这种情况下,虚表的数量会大于基类的数量。


总结

类的特征/继承结构 虚函数表 (vtable) 数量 对象中的虚指针 (vptr) 数量
无虚函数的普通类 0 0
包含虚函数的基类 1 1
单继承(基类有虚函数) 1 1
多重继承(N 个基类有虚函数) N N

注:C++ 标准并没有硬性规定虚函数表必须如何实现(这属于编译器 ABI 范畴),但主流编译器(GCC/Clang/MSVC)在处理虚表数量的逻辑上基本保持一致。

相关推荐
raindayinrain1 小时前
c++并发
c++
j7~1 小时前
【C++】智能指针的使用及其原理--详解
c++·c++11·内存泄漏·智能指针·raii·boost智能指针
刀法如飞1 小时前
《理解道德经》简版第5章:天地不仁,以万物为刍狗
面试·机器人
wuyk5552 小时前
107.FreeRTOS 链表深度解析:从原理到面试满分答案
c语言·开发语言·数据结构·stm32·单片机·链表·面试
Persistent的粽子!2 小时前
C++:类与对象(一)
开发语言·c++·经验分享·笔记
库玛西3 小时前
深入浅出Linux select网络模型:从底层位图原理到C++面向对象高级封装
linux·服务器·网络·c++·ubuntu
2402_882893863 小时前
深入浅出 unordered_map 与 unordered_set——从使用到底层差异
c++·哈希·unordered_map·unordered_set
今天要早睡_3 小时前
C++ 核心语法速过:命名空间、引用、函数重载与 nullptr 深度解析
android·java·c++
汉克老师4 小时前
CSP-J 初赛(以满分为目标):第二十七课 《图的遍历——BFS广度优先搜索——像“水波纹”一样,一层一层地搜索》
c++·csp-j·小学生·学c++编程
闻缺陷则喜何志丹4 小时前
【动态规划】P3609 [USACO17JAN] Hoof, Paper, Scissor G
c++·算法·动态规划·洛谷