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;
}
执行过程(底层原理):
- 创建
Derived
对象,构造函数自动设置vptr
,指向Derived
的虚表; - 虚表中
speak()
的指针是&Derived::speak()
; - 调用
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;
};
你不会在代码中显式看到 vptr
和 vtable
,它们是编译器隐藏实现的。
五、相关细节注意
情况 | 说明 |
---|---|
类没有虚函数 | 不生成 vtable,不支持运行时多态 |
虚函数未被重写 | 虚表中仍然是基类函数指针 |
多重继承 | 每个父类一套虚表和一个 vptr |
析构函数建议设为 virtual | 防止只析构父类对象导致内存泄漏 |
构造函数中调用虚函数 | 不会发生多态,vptr 还没完全初始化 |
六、下节预告
1.多重继承下的虚表结构
2.析构函数不设为virtual导致内存泄漏示例
相关文章:
C++中的虚表和虚表指针的原理和示例
一、基本概念 1. 什么是虚函数(virtual function)? 虚函数是用 virtual 关键字修饰的成员函数,支持运行时多态(dynamic polymorphism)。通过基类指针或引用调用派生类重写的函数。 class Base { public:…...

qemu热迁移后内存占用突增问题
1.问题描述 虚拟机配置了memoryBackingmemfd的情况下,热迁移虚拟机后,在目的节点 qemu-kvm 进程占用 rss 会突增很多。 如果去掉这个配置没这个现象。 <memoryBacking><source typememfd/> </memoryBacking>2.问题现象 2.1 不配置…...

鸿蒙 Core File Kit(文件基础服务)之简单使用文件
查看常用的沙箱目录 应用沙箱文件访问关系图 应用文件目录结构图 查看常用的沙箱目录 Entry Component struct Index {build() {Button(查看常用的沙箱目录).onClick(_>{let ctx getContext() // UI下只能使用这个方法,不能 this.contextconsole.log(--应用缓存…...
AI 检测原创论文:技术迷思与教育本质的悖论思考
当高校将 AI 写作检测工具作为学术诚信的 "电子判官",一场由技术理性引发的教育异化正在悄然上演。GPT-4 检测工具将人类创作的论文误判为 AI 生成的概率高达 23%(斯坦福大学 2024 年研究数据),这种 "以 AI 制 AI&…...

基于Qt的app开发第七天
写在前面 笔者是大一下计科生,标题这个项目是笔者这个学期的课设,与学长共创,我负责客户端部分,现在已经实现了待办板块的新建、修改。 这个项目目前已经走上正轨了,博主也实现了主要功能的从无到有ÿ…...

目标检测任务常用脚本1——将YOLO格式的数据集转换成VOC格式的数据集
在目标检测任务中,不同框架使用的标注格式各不相同。常见的框架中,YOLO 使用 .txt 文件进行标注,而 PASCAL VOC 则使用 .xml 文件。如果你需要将一个 YOLO 格式的数据集转换为 VOC 格式以便适配其他模型,本文提供了一个结构清晰、…...

NLTK库: 数据集3-分类与标注语料(Categorized and Tagged Corpora)
NLTK库: 数据集3-分类与标注语料(Categorized and Tagged Corpora) 1.二分类语料 主要是电影语料,和情绪(积极消极、主观客观)有关,有以下2个语料: 1.1 movie_reviews: IMDb 影评 IMDb(Internet Movie …...

uni-app学习笔记五-vue3响应式基础
一.使用ref定义响应式变量 在组合式 API 中,推荐使用 ref() 函数来声明响应式状态,ref() 接收参数,并将其包裹在一个带有 .value 属性的 ref 对象中返回 示例代码: <template> <view>{{ num1 }}</view><vi…...

ElasticSeach快速上手笔记-入门篇
由来 Elasticsearch 是一个基于 Apache Lucene 构建的分布式、高扩展、近实时的搜索与数据分析引擎,能够高效处理结构化和非结构化数据的全文检索及复杂分析 搜索,即用户在平台如百度进行输入关键词,由后端给出搜索结果数据进行返回&#x…...
eward hacking 问题 强化学习钻空子
Reward Hacking的本质是目标对齐(Goal Alignment)失败 “Reward hacking”(奖励黑客)是强化学习或AI系统中常见的问题,通俗地说就是: AI模型“钻空子”,用投机取巧的方式来拿高分,而…...
uniapp开发4--实现耗时操作的加载动画效果
下面是使用 Vue 组件的方式,在 uni-app 中封装耗时操作的加载动画效果及全屏遮罩层的组件的示例。 组件结构: components/loading.vue: 组件文件,包含 HTML 结构、样式和 JS 逻辑。 代码: <template><view class&…...

《ffplay 读线程与解码线程分析:从初始化到 seek 操作,对比视频与音频解码的差异》
1 read-thread 1.1 初始化部分 1.分配. avformat_alloc_context 创建上下⽂ ic avformat_alloc_context();if (!ic) {av_log(NULL, AV_LOG_FATAL, "Could not allocate context.\n");ret AVERROR(ENOMEM);goto fail;}2 ic->interrupt_callback.callback deco…...

MySQL推荐书单:从入门到精通
给大家介绍一些 MySQL 从入门到精通的经典书单,可以基于不同学习阶段的需求进行选择。 入门 MySQL必知必会 这本书继承了《SQL必知必会》的优点,专门针对 MySQL 用户,没有过多阐述数据库基础理论,而是紧贴实战,直接从…...
用 Rust 搭建一个优雅的多线程服务器:从零开始的详细指南
嘿,小伙伴们!今天咱们来聊聊怎么用 Rust 搭建一个牛气哄哄的多线程服务器,还能在需要的时候优雅地关机。为啥要用 Rust 呢?因为 Rust 是个超级靠谱的语言,它能保证内存安全,写并发代码的时候不用担心那些让…...
redis 数据结构-01( SET、GET、DEL)
使用 Redis 字符串:SET、GET、DEL Redis 字符串是用于存储和操作文本或二进制数据的基本数据类型。它们是 Redis 中最简单但功能最丰富的数据结构,可作为构建更复杂结构的基石。了解如何有效地使用字符串对于充分利用 Redis 的缓存、会话管理以及其他各…...

【Nacos】env NACOS_AUTH_TOKEN must be set with Base64 String.
【Nacos】env NACOS_AUTH_TOKEN must be set with Base64 String. 问题描述 env NACOS_AUTH_TOKEN must be set with Base64 String.原因分析 从错误日志中可以看出,Nacos 启动失败的原因是缺少必要的环境变量 NACOS_AUTH_TOKEN。 NACOS_AUTH_TOKEN: Nacos 用于生…...

秋招准备——2.跨时钟相关
格雷码异步FIFO跨时钟域处理 格雷码 一、格雷码规律 相邻性:相邻两个数的格雷码只有一位不同,例如: 0000 → 0001(仅最低位变化)0001 → 0011(仅次低位变化)0011 → 0010(仅最低位…...

激光打印机常见打印故障简单处理意见
一、 问题描述: 给打印机更换新的硒鼓时拉开硒鼓封条时有微量碳粉带出; 原因: 出厂打印测试时,可能会有微量碳粉在磁辊上或者磁辊仓; 解决方法: 擦干净即可正常使用; 二、 问题描述&…...
语言学中的对象语言与元语言 | 概念 / 区别 / 实例分析
注:英文引文,机翻未校。 语言学中的“对象语言”和“元语言” 刘福长 现代外语 1989年第3期(总第45期) 在阅读语言学著作时,我们有时会遇到这样两个术语:对象语言(object language࿰…...

【2025最新】Windows系统装VSCode搭建C/C++开发环境(附带所有安装包)
文章目录 为什么选择VSCode作为C/C开发工具?一、VSCode安装过程(超简单!)二、VSCode中文界面设置(再也不用对着英文发愁!)三、安装C/C插件(编程必备神器!)四、…...

MYSQL 查询去除小数位后多余的0
MYSQL 查询去除小数位后多余的0 在MySQL中,有时候我们需要去除存储在数据库中的数字字段小数点后面多余的0。这种情况通常发生在处理金额或其他需要精确小数位的数据时。例如,数据库中存储的是decimal (18,6)类型的数据,但在页面展示时不希望…...

基于GF域的多进制QC-LDPC误码率matlab仿真,译码采用EMS算法
目录 1.算法仿真效果 2.算法涉及理论知识概要 3.MATLAB核心程序 4.完整算法代码文件获得 1.算法仿真效果 matlab2022a仿真结果如下(完整代码运行后无水印): 本课题实现的是四进制QC-LDPC 仿真操作步骤可参考程序配套的操作视频。 2.算…...

Vitrualbox完美显示系统界面(只需三步)
目录 1.使用vitrualbox的增强功能:编辑 2.安装增强功能(安装完后要重启虚拟机): 3. 调整界面尺寸(如果一个选项不行的话,就多试试其他不同的百分比): 先看看原来的,…...

王炸组合!STL-VMD二次分解 + Informer-LSTM 并行预测模型
往期精彩内容: 单步预测-风速预测模型代码全家桶-CSDN博客 半天入门!锂电池剩余寿命预测(Python)-CSDN博客 超强预测模型:二次分解-组合预测-CSDN博客 VMD CEEMDAN 二次分解,BiLSTM-Attention预测模型…...

n8n 修改或者智能体用文档知识库创建pdf
以下是对 Nextcloud、OnlyOffice、Seafile、Etherpad、BookStack 和 Confluence 等本地部署文档协作工具的综合评测、对比分析和使用推荐,帮助您根据不同需求选择合适的解决方案。 🧰 工具功能对比 工具名称核心功能本地部署支持适用场景优势与劣势Next…...

论坛系统(中-1)
软件开发 编写公共代码 定义状态码 对执⾏业务处理逻辑过程中可能出现的成功与失败状态做针对性描述(根据需求分析阶段可以遇见的问题提前做出定义),⽤枚举定义状态码,先定义⼀部分,业务中遇到新的问题再添加 定义状态码如下 状态码类型描…...

FPGA+ESP32 = GameBoy 是你的童年吗?
之前介绍的所有的复古游戏机都是基于Intel-Altera FPGA制作的,今天就带来一款基于AMD-Xilinx FPGA的复古掌上游戏机-Game Bub。 Game Bub是一款掌上游戏机,旨在畅玩 Game Boy、Game Boy Color 和 Game Boy Advance 游戏。与大多数现代掌上游戏机一样&…...

3D迷宫探险:伪3D渲染与运动控制的数学重构
目录 3D迷宫探险:伪3D渲染与运动控制的数学重构引言第一章 伪3D渲染引擎1.1 射线投射原理1.2 纹理透视校正第二章 迷宫生成算法2.1 图论生成模型2.2 复杂度控制第三章 第一人称控制3.1 运动微分方程3.2 鼠标视角控制第四章 碰撞检测优化4.1 层级检测体系4.2 滑动响应算法第五章…...

【金仓数据库征文】_金仓数据库在金融行业的两地三中心容灾架构实践
金仓数据库在金融行业的两地三中心容灾架构实践 🌟嗨,我是LucianaiB! 🌍 总有人间一两风,填我十万八千梦。 🚀 路漫漫其修远兮,吾将上下而求索。 引言 随着国家对信息技术应用创新࿰…...

Python作业练习3
任务简述 字符田字格绘制 代码实现 def print_tianzige():for i in range(11):if i in [0, 5, 10]:print("" "-----" * 2)else:print("|" " |" * 2)print_tianzige() 结果展示...