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

C++】透视C++多态:从虚函数表到底层内存布局的完全拆解C++】透视C++多态:从虚函数表到底层内存布局的完全拆解

1. 多态原理下面这段代码中Buy()函数如果传入的是Person调用的就是Person::BuyTicket()传Student调用的是Student::BuyTicket。这样就构成了多态而多态的调用实现是依靠运行时去指向对象的虚表中查调用的函数地址。代码语言javascriptAI代码解释class Person { public: Person(const char* name 张三) :_name(name) {} virtual void BuyTicket() { cout _name 购票,需要排队,每人 100 endl; } protected: string _name; }; class Student : public Person { public: Student(const char* name) :_name(name) {} virtual void BuyTicket() { cout _name 购票,需要排队,每人 50 endl; } private: string _name; }; void Buy(Person* p) { p-BuyTicket(); } int main() { Person p(张三); Buy(p); Student st(张同学); Buy(st); return 0; }通过监视窗口我们可以发现Person指向对象p时p-BuyTicket()在p的虚表中找到虚函数是Person::TicketStudent指向对象st时st-BugTicket在st的虚表中找到虚函数是Student::Ticket通过查找不同的虚函数就实现了不同的对象调用会有不同的行为也就是多态我们再明确一下实现多态的两个条件存在虚函数、需要对象指针或引用调用虚函数通过反汇编窗口可以发现构成了多态之后函数的调用是在运行了程序过程中去对象中取的而不是编译时就决定的如果不是多态函数调用会在编译时就决定好多态调用运行时决议运行时才确定函数的地址普通函数编译时决议编译时确认调用函数的地址2. 动态绑定与静态绑定静态绑定前期绑定编译时就决定了调用哪个函数根据变量或表达式的静态类型决定也就形成了静态多态如函数重载动态绑定后期绑定在程序运行时根据拿到的具体类型来确定函数的具体行为也就形成动态动态如下面这个和上面那个p-BuyTicket()对比就知道动态绑定和静态绑定的区别3. 单继承和多继承中的虚函数表3.1. 单继承中的虚函数表代码语言javascriptAI代码解释class Base { public: virtual void Func1() { cout Base::Func1() endl; } virtual void Func2() { cout Base::Func2() endl; } private: int _b 1; }; class Derive :public Base { public: virtual void Func1() { cout Derive::Func1() endl; } virtual void Func3() { cout Derive::Func3() endl; } virtual void Func4() { cout Derive::Func4() endl; } private: int _d 2; }; int main() { Base b; Derive d; return 0; }通过调试时我们发现似乎有些问题理论上派生类d应该会有三个虚函数继承基类的两个新增加的两个但是我们发现虚表中只有两个指针我们看不到Func3()和Func4()这里是编译器隐藏了这两个函数可以认为是VS的一个Bug。这里我们采用比较底层的方式打印出虚表的指针首先我们明确一点虚函数指针会隐藏的存储在对象内存的开头我们先 b 取地址然后强制转换成三重指针 (void***)(d)这相当于告诉编译器将这块内存看做指向void**的指针然后进行解引用 *(void***)(d)这也就是对象开头的虚函数表指针代码语言javascriptAI代码解释// 打印虚表并执行函数 void PrintVFTable_Safe(void** vtable, int max_entries 10) { cout Virtual Table Address: vtable endl; if (vtable nullptr) { cout Invalid vtable pointer! endl; return; } for (int i 0; i max_entries; i) { // 检查地址是否有效 if (vtable[i] nullptr || (uintptr_t)vtable[i] 0x1000) { cout [ i ]: END OF TABLE endl; break; } cout [ i ]: vtable[i]; // 直接执行函数 typedef void(*FuncPtr)(); FuncPtr func (FuncPtr)vtable[i]; cout - ; func(); // 执行函数 // 安全限制避免无限循环 if (i max_entries - 1) { cout ... (reached max entries) endl; break; } } cout endl; } int main() { Base b; Derive d; void** vtable_b *(void***)(b); void** vtable_d *(void***)(d); cout Base Virtual Table endl; PrintVFTable_Safe(vtable_b); cout Derive Virtual Table endl; PrintVFTable_Safe(vtable_d); return 0; }3.2. 多继承中的虚函数表下面我们给出一段多继承的代码来分析一下代码语言javascriptAI代码解释#include iostream using namespace std; class Base1 { public: virtual void Func1() { cout Base1::Func1() endl; } virtual void Func2() { cout Base1::Func2() endl; } private: int _b1 1; }; class Base2 { public: virtual void Func1() { cout Base2::Func1() endl; } virtual void Func2() { cout Base2::Func2() endl; } private: int _b2 1; }; class Derive :public Base1, public Base2 { public: virtual void Func1() { cout Derive::Func1() endl; } virtual void Func3() { cout Derive::Func3() endl; } private: int _d1 2; }; // 打印虚表并执行函数 void PrintVFTable_Safe(void** vtable, int max_entries 10) { cout Virtual Table Address: vtable endl; if (vtable nullptr) { cout Invalid vtable pointer! endl; return; } for (int i 0; i max_entries; i) { // 检查地址是否有效 if (vtable[i] nullptr || (uintptr_t)vtable[i] 0x1000) { cout [ i ]: END OF TABLE endl; break; } cout [ i ]: vtable[i]; // 直接执行函数 typedef void(*FuncPtr)(); FuncPtr func (FuncPtr)vtable[i]; cout - ; func(); // 执行函数 // 安全限制避免无限循环 if (i max_entries - 1) { cout ... (reached max entries) endl; break; } } cout endl; } int main() { Derive d; void** vtable_d *(void***)(d); PrintVFTable_Safe(vtable_d); return 0; }构成这样一个继承关系我们通过调试先来看一下对象d的虚函数指针然后通过打印的结果我们可看出派生类新增的虚函数一般会储存在第一个继承基类的虚函数表中

相关文章:

C++】透视C++多态:从虚函数表到底层内存布局的完全拆解C++】透视C++多态:从虚函数表到底层内存布局的完全拆解

1. 多态原理下面这段代码中,Buy()函数,如果传入的是Person调用的就是Person::BuyTicket(),传Student调用的是Student::BuyTicket。这样就构成了多态,而多态的调用实现,是依靠运行时,去指向对象的虚表中查调…...

配置nginx访问本地静态资源、本地图片、视频。

配置nginx访问本地静态资源、本地图片、视频。 1、进入nginx安装目录2、打开conf文件夹下的nginx.conf文件,进行配置。 步骤:①打开文件后找到http中的server ②再添加一个server配置,将需要从其他电脑访问的本地路径进行配置。配置内容如下&…...

hardhat 单元测试时如何观察gas消耗情况

文章目录前言hardhat 单元测试时如何观察gas消耗情况1. 安装依赖与配置2. 演示示例前言 如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。   而且听说点赞的人每天的运气都不会太差,实在…...

配置 Redis

介绍 Redis:缓存框架(工具) why使用Redis Redis介绍 Redis安装:(推荐安装Linux);重新打包,打包一份Windows(不是官方出的) 简单使用; Redis集群:(负载均衡); 优点: 使用各种语言都可以链接 redis在哪里起到作用 最牛带的Redis:即放内存,又放硬盘;(放内存的频繁要比硬盘的高很多…...

腾讯云“当前登录IP”与个人实际IP不符

2026/3/13日购买了腾讯云服务器,准备用Navicat连接腾讯云上部署的mysql时连接失败。正常排查问题,开启防火墙当前登录ip允许访问3306端口开发(相当于阿里云的安全组),关闭镜像实例的防火墙(已关闭&#xff…...

适用于IntelliJ IDEA 2024.1.2部署Tomcat的完整方法,以及笔者踩的坑,避免高血压,保姆级教程

Tips:创建部署Tomcat直接跳转到四 一、软件准备 笔者用的是IntelliJ IDEA 2024.1.2和Tomcat 8.5。之前我使用的是Tomcat 10,但遇到了许多问题。其中一个主要问题是需要使用高于1.8版本的JDK,为此我下载了新的JDK版本,但这又引发了更多的兼容性…...

如何优雅记录 HTTP 请求/响应数据?

1. 引言在现代软件开发和运维中,HTTP 协议作为应用层最常见的通信协议,承载了无数的业务请求和响应。无论是 Web 应用、移动 App 后端,还是微服务间的调用,HTTP 都是主要的交互方式。因此,记录 HTTP 请求和响应的数据变…...

再见 Java 8,Java 17 来了!2万字详解升级指南与新特性盛宴

前言2021年9月,Java 17 正式发布,作为继 Java 11 之后的又一个长期支持(LTS)版本,它带来了无数令人兴奋的新特性、性能改进和安全增强。对于仍停留在 Java 8 的开发者而言,是时候挥手告别这个服役近十年的经…...

深入鸿蒙生态:高级Android开发工程师的挑战与机遇

随着万物互联时代的加速到来,操作系统生态正经历深刻变革。华为推出的HarmonyOS(鸿蒙操作系统),以其分布式架构、流畅体验和全场景智慧能力,为开发者开辟了新的疆域。对于经验丰富的Android开发工程师而言,拥抱HarmonyOS不仅是技术栈的扩展,更是职业发展的重要机遇。本文…...

鸿蒙生态崛起:深度解析鸿蒙开发人员职责、技能要求与面试指南

前言随着万物互联时代的加速到来,鸿蒙操作系统(HarmonyOS)作为面向未来的全场景分布式操作系统,正展现出强大的生命力和广阔的发展前景。其“一次开发,多端部署”的理念,以及对分布式能力的原生支持&#x…...

厂长资源 1.0.4 | Czzy超清影视聚合站.官方入口

厂长资源(Czzy)是一个在国内影视爱好者中极具口碑的免费在线影视聚合平台,以其“画质至上、界面清爽、更新极速”的核心理念著称。该平台不依赖繁琐的注册登录机制,主打“打开即看”的极简体验,致力于为用户提供无广告…...

CMake 报错 Failed to find required Qt component WebEngineWidgets

这个问题看上去和《CMake 报错:Failed to find optional Qt component Core5Compat》类似,但是解决起来要麻烦很多。Qt 的 WebEngine 模块是基于 Chromium 开发的 Web 引擎,它不是一个独立的浏览器,而是一个深度集成 Chromium 渲染…...

vscode插件突然安装不上

整了半天, 将本地的clash退出,然后将设置中的http://127.0.0.1:7890去掉...

什么是字符串反转?

将字符串的字符顺序完全颠倒的操作。例如 "Hello" → "olleH",是编程基础操作,用于算法练习、回文判断等场景。 核心实现方法 1. 用语言内置功能Python:"hello"[::-1] Java:new StringBuilder(&quo…...

【系统心法】别让你的机械臂死于“低级错误”!重演火星探路者灾难,手撕 RTOS 优先级反转与防瘫痪架构

摘要:你以为给核心任务设置了 Priority Highest,它就一定能随时抢占 CPU 吗?在复杂的 RTOS 抢占式调度中,一个微不足道的低优先级日志任务,完全有可能把最高优先级的运动控制任务死死卡住,导致系统彻底瘫痪…...

Python itertools模块详细教程

Python itertools模块详细教程 1. 模块简介 itertools模块是Python标准库中的一个重要模块,提供了一系列快速、节省内存的迭代器函数。这些函数受到APL、Haskell和SML等函数式编程语言的启发,用于创建各种类型的迭代器,帮助开发者更高效地处…...

双矢量控制与电流预测模型

模型预测电流控制,双矢量(有效电压矢量和零矢量占空比分配),两个非零矢量情况。在电机控制领域里,电流环的快速响应和低纹波始终是个技术难点。传统单矢量模型预测控制容易产生明显震荡,就像新手司机猛踩油…...

Hana Studio vs SAP GUI:ABAP开发工具选择指南与实战对比

Hana Studio vs SAP GUI:ABAP开发者的十字路口与实战抉择 在SAP ABAP开发的世界里,工具的选择从来不是一件小事。它关乎你每天敲击键盘的流畅度,关乎调试时能否快速定位到那个恼人的逻辑错误,更关乎在复杂项目压力下,你…...

MAI-UI-8B MySQL数据库操作指南:自动化数据管理方案

MAI-UI-8B MySQL数据库操作指南:自动化数据管理方案 1. 引言 你是不是经常被繁琐的数据库操作搞得头大?每天重复执行相同的查询、更新、备份任务,不仅浪费时间还容易出错。现在有了MAI-UI-8B,这一切都可以自动化了。 MAI-UI-8B…...

Fish-Speech-1.5效果展示:13种语言语音合成对比

Fish-Speech-1.5效果展示:13种语言语音合成对比 1. 多语言语音合成的新标杆 语音合成技术最近又有了新突破,Fish-Speech-1.5作为新一代文本转语音模型,一口气支持了13种不同语言的语音合成。这可不是简单的语言切换,而是真正做到…...

YOLOv13镜像使用问题集锦:常见错误与解决方法汇总

YOLOv13镜像使用问题集锦:常见错误与解决方法汇总 YOLOv13 官版镜像凭借其开箱即用的便利性和集成的 Flash Attention v2 加速能力,成为了许多开发者和研究者的首选。然而,在实际部署和使用过程中,从环境配置到模型训练&#xff…...

从零构建智能客服聊天产品原型:技术选型与实战避坑指南

最近在做一个智能客服聊天产品的原型,团队里的小伙伴对对话管理、意图识别这些概念都比较模糊,踩了不少坑。今天就把我们基于 Python Flask Rasa 这套技术栈,从零搭建一个可运行、可扩展的原型过程记录下来,重点分享技术选型的考…...

Gemma-3 Pixel Studio企业落地:制造业设备图故障识别与维修建议生成

Gemma-3 Pixel Studio企业落地:制造业设备图故障识别与维修建议生成 1. 引言:当工厂设备“开口说话” 想象一下这个场景:工厂里一台价值百万的数控机床突然报警停机,维修工程师匆匆赶到现场。面对复杂的控制面板、密密麻麻的线缆…...

衡山派Luban-Lite开发板CAP0捕获功能参数配置详解

衡山派Luban-Lite开发板CAP0捕获功能参数配置详解 最近在衡山派Luban-Lite开发板上做脉冲宽度测量项目,发现很多朋友对如何启用和配置输入捕获(CAP)功能有些困惑。特别是怎么通过menuconfig这个图形化配置工具,一步步把CAP0通道给…...

国产化FTP替代方案哪个好?性能与安全双突破!

在信创产业加速推进与国产化替代浪潮的双重驱动下,政府、金融、医疗、能源等关键行业对文件传输的自主可控、安全合规要求日益严苛。传统FTP的技术缺陷逐渐暴露,难以满足新时代数据传输需求,寻找优质的国产化FTP替代方案成为企业数字化转型的…...

Qwen3-ASR-1.7B企业应用:医院门诊语音记录结构化+ICD编码辅助提示

Qwen3-ASR-1.7B企业应用:医院门诊语音记录结构化ICD编码辅助提示 1. 医疗语音识别的痛点与机遇 在医院门诊环境中,医生每天需要接诊大量患者,记录病历、诊断意见和治疗方案。传统的手写记录或键盘输入方式存在诸多痛点:医生需要…...

BI 中的数据仓库,一文通透

一谈到BI总是离不开数据仓库,有很多人不太明白数据仓库到底在商业智能BI项目中有什么作用,对数据仓库的作用有些争论,所以今天来聊聊数据仓库,探讨下数据仓库的真正用处。数据仓库数据库类型的选择从技术实现角度上来说&#xff0…...

LeetCode 3296. 移山所需的最少秒数 技术解析(含完整可运行代码)

摘要:本文针对LeetCode 3296题“移山所需的最少秒数”,从问题本质出发,拆解题意、分析核心痛点,推导最优解题思路(二分查找),详细讲解算法原理、边界处理及代码实现细节,结合示例验证…...

云端部署 OpenClaw 通过插件操作本机浏览器

前言:最近openclaw大火,网上的热度也是水涨船高,我的openclaw是部署到云服务器上,想让他操控我本地的电脑进行一些简单的网页操作,在网上搜索了相关资料,有了这篇教程,后续会分享更多开发实战干…...

判断企业是否需要WMS的核心标准

业务规模与复杂度:当SKU数量超过1000或日均订单量超过50单时,Excel管理易出现数据混乱、版本冲突等问题。WMS系统能实现条码化、批次管理、货位优化等功能,降低人工干预。人力成本与效率:Excel需专人维护,按1名员工年薪…...