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

C++虚函数表(虚表Virtual Table,简称vtable、VFT)(编译器为支持运行时多态(动态绑定)而自动生成的一种内部数据结构)虚函数指针vptr

文章目录

      • **1. 虚函数表的核心概念**
        • - **虚函数表(vtable)**:
        • - **虚函数指针(vptr)**:
      • **2. 虚函数表的生成与工作流程**
        • **生成时机**
          • - **当一个类中至少有一个虚函数时**,编译器会为该类生成一个虚函数表。
          • - **派生类继承虚函数表**:
        • **调用流程**
          • 1. **对象创建时**:
          • 2. **调用虚函数时**:
      • **3. 示例代码解析**
        • - 以下代码展示了虚函数表的工作原理
        • - **虚函数表的生成**:
        • - **调用过程**:
      • **4. 虚函数表的内存布局**
        • - 以一个简单的类为例
        • - **对象内存布局**:
        • - **虚函数表结构**:
      • **5. 虚函数表的注意事项**
        • 1. **性能开销**:
        • 2. **纯虚函数与抽象类**:
        • 3. **多继承与虚函数表**:
        • 4. **编译器相关**:
      • **6. 虚函数调用流程图**
      • **7. 总结**

C++中的 虚函数表(Virtual Table,简称 vtable)是编译器为支持 运行时多态(动态绑定)而自动生成的一种内部数据结构。它的核心作用是通过 虚函数指针(vptr)和虚函数表的配合,实现基类指针或引用调用派生类重写函数的能力。


1. 虚函数表的核心概念

- 虚函数表(vtable)

每个包含虚函数的类都会有一个虚函数表。这个表是一个指针数组,存储了该类所有虚函数的地址。例如:

  • 如果一个类有3个虚函数,虚函数表就包含3个指针,分别指向这3个函数的实现。
  • 如果派生类重写了某个虚函数,派生类虚函数表中对应位置的指针会被替换为派生类的函数地址。
- 虚函数指针(vptr)

每个包含虚函数的对象在内存中会隐式地包含一个指针(vptr),指向该对象所属类的虚函数表。

  • vptr通常位于对象内存布局的最前面(具体位置可能因编译器而异)。
  • 当通过基类指针或引用调用虚函数时,程序会通过vptr查找虚函数表,找到正确的函数地址并执行。

2. 虚函数表的生成与工作流程

生成时机
- 当一个类中至少有一个虚函数时,编译器会为该类生成一个虚函数表。
- 派生类继承虚函数表
  • 如果派生类没有重写基类的虚函数,则虚函数表中直接继承基类的虚函数地址。
  • 如果派生类重写了某个虚函数,则虚函数表中对应位置的指针会被更新为派生类的函数地址。
调用流程
1. 对象创建时

编译器会自动初始化对象的vptr,使其指向该类的虚函数表。

2. 调用虚函数时
  • 程序通过对象的vptr找到虚函数表。
  • 根据虚函数表中的索引(与函数声明顺序一致)找到对应的函数地址。
  • 调用该地址指向的函数(可能是基类或派生类的实现)。

3. 示例代码解析

- 以下代码展示了虚函数表的工作原理
#include <iostream>
using namespace std;class Base {
public:virtual void func() { cout << "Base::func()" << endl; }
};class Derived : public Base {
public:void func() override { cout << "Derived::func()" << endl; }
};int main() {Base* ptr = new Derived();ptr->func();  // 输出 "Derived::func()"delete ptr;return 0;
}
- 虚函数表的生成
  • Base类有一个虚函数func(),因此编译器为Base生成一个虚函数表,表中存储Base::func()的地址。
  • Derived类重写了func(),因此编译器为Derived生成一个新的虚函数表,表中存储Derived::func()的地址。
- 调用过程
  • ptrBase*类型,但指向Derived对象。
  • 调用ptr->func()时,程序通过Derived对象的vptr找到Derived的虚函数表,调用Derived::func()

4. 虚函数表的内存布局

- 以一个简单的类为例
class Base {
public:virtual void func1() {}virtual void func2() {}
};
- 对象内存布局

每个Base对象的内存布局如下:

[vptr] -> 指向Base的虚函数表
[其他成员变量]
Base
+virtual void func1()
+virtual void func2()
«data»
BaseObject
vptr --> Base
data1: int
data2: double
- 虚函数表结构
Base的虚函数表:
+-----------------+
| func1() 的地址  |
+-----------------+
| func2() 的地址  |
+-----------------+
Base的虚函数表
func1() 地址
func2() 地址

5. 虚函数表的注意事项

1. 性能开销
  • 调用虚函数需要通过两次间接寻址(vptr → 虚函数表 → 函数地址),比直接调用普通函数稍慢。
  • 每个对象需要额外存储一个vptr,增加了内存占用。
2. 纯虚函数与抽象类
  • 如果类中包含纯虚函数(virtual void func() = 0;),则该类为抽象类,不能实例化对象。
  • 纯虚函数在虚函数表中通常用特殊标记(如NULL)表示。
3. 多继承与虚函数表
  • 多继承情况下,对象可能包含多个vptr,分别指向不同基类的虚函数表。
  • 虚函数表的管理会更复杂,但核心原理与单继承相同。
Derived对象
vptr1 (Base1)
vptr2 (Base2)
Base1::func()
Base2::func()
4. 编译器相关
  • 虚函数表是编译器的实现细节,C++标准未规定具体实现方式。主流编译器(如GCC、MSVC)均采用类似机制。

6. 虚函数调用流程图

以下是虚函数调用的完整流程:

Base* ptr = new Derived();
ptr->func()
vptr 指向 Derived 的虚函数表?
查找虚函数表中 func() 的地址
调用 Derived::func()
查找虚函数表中 func() 的地址
调用 Base::func()

7. 总结

虚函数表是C++实现运行时多态的核心机制。通过虚函数表和虚函数指针的配合,C++能够在运行时根据对象的实际类型动态选择正确的函数实现。这种机制虽然带来了一定的性能和内存开销,但极大地增强了代码的灵活性和可扩展性,是面向对象编程中多态特性的基石。

相关文章:

  • PPT转图片拼贴工具 v1.0
  • dvwa11——XSS(Reflected)
  • 【Maniskill】使用Ppo的官方基线训练时出现指标突然“塌陷”的现象
  • CSP-VP37th
  • ML Kit与YOLO:移动AI与实时检测终极对决
  • 前缀和题目:逐步求和得到正数的最小值
  • 打造智慧医疗枢纽,香港维尔利引领东南亚健康科技升级
  • 【Docker管理工具】部署Docker可视化管理面板Dpanel
  • LoRA:大模型高效微调的低秩之道——原理解析与技术实现
  • 【实施指南】Android客户端HTTPS双向认证实施指南
  • 摄像机ISP处理流程
  • 【华为云Astro-服务编排】服务编排使用全攻略
  • NLP学习路线图(二十六):自注意力机制
  • NC | 基于语言模型的药物设计新方法
  • Spring @Scheduled vs XXL-JOB vs DolphinScheduler vs Airflow:任务调度框架全景对比
  • 网页抓取混淆与嵌套数据处理流程
  • 检测到 #include 错误。请更新 includePath。已为此翻译单元(D:\软件\vscode\test.c)禁用波形曲线
  • BLOB 是用来存“二进制大文件”的字段类型
  • QMetaObject::invokeMethod调用失败
  • 基于rpc框架Dubbo实现的微服务转发实战
  • 价格列表 wordpress/seo怎么推广
  • php动态网站设计/免费b2b推广网站大全
  • 律师网站建设建议/百度推广非企代理
  • 设计公司官方网站/杭州seo关键词优化公司
  • 导师让做网站/品牌营销公司
  • 本省网站建设建议/站长之家ip地址查询