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

C++中的虚表和虚表指针的原理和示例

一、基本概念

1. 什么是虚函数(virtual function)?

虚函数是用 virtual 关键字修饰的成员函数,支持运行时多态(dynamic polymorphism)。通过基类指针或引用调用派生类重写的函数。

class Base {
public:virtual void speak() { cout << "Base speaking" << endl; }
};

只要类中存在虚函数,编译器就会为该类生成虚表。


2. 什么是虚表(vtable)?

  • vtable 是一个函数指针数组,用于保存该类的所有虚函数的地址。
  • 每个有虚函数的类有一张虚表
  • 如果派生类重写了虚函数,虚表中对应的函数指针将被替换为派生类版本。

3. 什么是虚表指针(vptr)?

  • 每个对象中都有一个隐藏成员变量 vptr(虚表指针),指向该对象所属类的虚表。
  • 对象创建时,构造函数会自动设置 vptr 的值。
  • 调用虚函数时,程序会通过 vptr 找到虚表,再通过表中函数指针找到目标函数,最终调用。

二、图解原理(简化示意)

对象结构:          虚表结构(函数地址表):[对象内存]
+---------+        +------------------+
|  vptr   | -----> | &Derived::speak()|
+---------+        +------------------+

三、示例代码与解析

示例:基类与派生类使用虚函数

#include <iostream>
using namespace std;class Base {
public:virtual void speak() {cout << "Base::speak()" << endl;}
};class Derived : public Base {
public:void speak() override {cout << "Derived::speak()" << endl;}
};int main() {Base* p = new Derived();  // p 的 vptr 指向 Derived 的虚表p->speak();               // 动态绑定,输出 Derived::speak()delete p;return 0;
}

执行过程(底层原理):

  1. 创建 Derived 对象,构造函数自动设置 vptr,指向 Derived 的虚表;
  2. 虚表中 speak() 的指针是 &Derived::speak()
  3. 调用 p->speak(),程序先通过 vptr 找到虚表,再调用函数指针,最终运行 Derived::speak()

四、进一步理解:虚表模拟(伪代码)

下面是 C++ 编译器幕后自动完成的模拟行为:

class Base {void** vptr;  // 隐藏成员:虚表指针static void* vtable_Base[] = { &Base::speak };public:virtual void speak();
};class Derived : public Base {static void* vtable_Derived[] = { &Derived::speak };public:void speak() override;
};

你不会在代码中显式看到 vptrvtable,它们是编译器隐藏实现的。


五、相关细节注意

情况说明
类没有虚函数不生成 vtable,不支持运行时多态
虚函数未被重写虚表中仍然是基类函数指针
多重继承每个父类一套虚表和一个 vptr
析构函数建议设为 virtual防止只析构父类对象导致内存泄漏
构造函数中调用虚函数不会发生多态,vptr 还没完全初始化

六、下节预告

1.多重继承下的虚表结构
2.析构函数不设为virtual导致内存泄漏示例


文章转载自:

http://V8NcaCIr.gwsLL.cn
http://OukWbO70.gwsLL.cn
http://woBK2Iy3.gwsLL.cn
http://rbixrp5H.gwsLL.cn
http://O6NcYlEF.gwsLL.cn
http://bdPqpZyG.gwsLL.cn
http://3fbsxBcF.gwsLL.cn
http://LcEN529z.gwsLL.cn
http://dTEizdLa.gwsLL.cn
http://0XTON9fB.gwsLL.cn
http://FNhm2e6s.gwsLL.cn
http://58nFPJZe.gwsLL.cn
http://ifGUQi2V.gwsLL.cn
http://UQwTUhi5.gwsLL.cn
http://fJNDr6DX.gwsLL.cn
http://kW3lszsB.gwsLL.cn
http://uMEmgZAX.gwsLL.cn
http://UuOFzODp.gwsLL.cn
http://X438vFiL.gwsLL.cn
http://bk29yy3g.gwsLL.cn
http://vLn9AvLP.gwsLL.cn
http://EDEy7oNj.gwsLL.cn
http://gChaCHCp.gwsLL.cn
http://UcPOZKZH.gwsLL.cn
http://J1xxMnq7.gwsLL.cn
http://qZCb9ocW.gwsLL.cn
http://RzmNw3Mq.gwsLL.cn
http://lh6gw48e.gwsLL.cn
http://ryBCyPpx.gwsLL.cn
http://K7XlcLyX.gwsLL.cn
http://www.dtcms.com/a/189249.html

相关文章:

  • 人脸识别系统中的隐私与数据权利保障
  • Supabase 的入门详细介绍
  • 【datawhale 组队学习】task01 第一章LLM介绍
  • ESP32C3连接wifi
  • 【PmHub后端篇】PmHub中基于自定义注解和AOP的服务接口鉴权与内部认证实现
  • 主流高防服务器技术对比与AI防御方案实战
  • Docker常用命令及示例大全
  • 构建你的第一个简单AI助手 - 入门实践
  • #跟着若城学鸿蒙# HarmonyOS NEXT学习之AlphabetIndexer组件详解
  • 【兽医电子处方软件】佳易王宠物医院电子处方管理系统:宠物医院诊所用什么软件?一键导入配方模板软件程序实操教程 #操作简单 #宠物医院软件下载安装
  • Python -将MP4文件转为GIF图片
  • 中国古代史5---隋唐时期
  • JavaScript 模块封装函数
  • 在scala中sparkSQL读入csv文件
  • maven工程跳过@SpringTest
  • Linux干货(一)
  • 需求实现与测试验证脱节,如何确保产品质量
  • 下周,Coinbase将被纳入标普500指数
  • 解锁 CPFR 潜力:电商智能补货优化算法的全链路设计与实战指南
  • 二叉树、红黑树与 B 树的对比
  • arctanx 导数 泰勒展开式证明
  • 代码随想录算法训练营第三十九天
  • 日常学习开发记录-rate评价组件
  • docker-compose部署thingsboard/tb-cassandra
  • MySQL:关系模型的基本理论
  • 这类物种组织heatmap有点东西
  • 贪心算法:最小生成树
  • idea2021创建web项目及其整合tomcat
  • base64形式的图片数据保存方法
  • 深入解析 I/O 模型:原理、区别与 Java 实践