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

C++ 虚表与多态:从源码到汇编的逐步解析

本文基于代码随想录最强八股文给出的C 源码与对应的x86-64System V ABI 风格反汇编按“程序运行流程”一步步解释对象内存里vptr虚表指针在哪构造函数如何写入 vptrAnimal*指针如何通过vtable 间接调用到Dog::speak()/Cat::speak()为什么会看到vtable for Animal16说明反汇编属于 GCC/Clang 常见的 Itanium C ABI 风格例如出现vtable for X、typeinfo for X、std::__cxx11::basic_string...等符号。不同编译器/优化等级会导致细节不同但核心机制一致。1. 源码回顾我们要解释的“多态点”在哪里源码节选classAnimal{protected:string name;public:Animal(string n):name(n){}virtualvoidspeak(){coutname is making a sound.endl;}};classDog:publicAnimal{public:Dog(string n):Animal(n){}voidspeak()override{coutname says: Woof!endl;}};classCat:publicAnimal{public:Cat(string n):Animal(n){}voidspeak()override{coutname says: Meow!endl;}};voidanimalSpeak(Animal*a){a-speak();}关键点只有一个Animal::speak()是virtual。因此当你写a-speak()时编译器必须在运行时根据a指向对象的真实类型Dog/Cat来决定调用哪个speak()。2. 对象内存布局vptr 在对象最前面name 紧随其后只要一个类里存在虚函数编译器通常会在对象里塞一个隐藏成员vptr指向虚表 vtable 的指针。在汇编中反复出现add rax, 8来访问name这表明对象布局为this 0 : vptr8 字节 this 8 : std::string name对象本体简图如下低地址 -------------------- | vptr (8B) | -- this 0 -------------------- | std::string name | -- this 8 -------------------- 高地址注意std::string的内部布局很复杂SSO、小字符串优化等本文不展开只把它当作一个需要“构造/析构”的成员对象即可。3. 运行流程总览main 里发生了什么main()的逻辑是构造Dog d(Buddy)构造Cat c(Kitty)调用animalSpeak(d)期望触发Dog::speak()调用animalSpeak(c)期望触发Cat::speak()退出 main析构c、析构d反汇编里你能看到类似逻辑层面call Dog::Dog(...)call Cat::Cat(...)call animalSpeak(Animal*)两次call Cat::~Cat()、call Dog::~Dog()离开作用域自动析构下面我们按这个流程逐段对齐。4. Step 1构造 Animal 子对象 —— vptr 先被写成 Animal 的 vtable4.1 Animal 构造函数做了两件事源码Animal(string n):name(n){}含义给对象写入 vptr因为 Animal 有虚函数构造成员name调用std::string的拷贝构造/构造4.2 汇编设置 vptr最关键的 1 行Animal::Animal(...)中有这一段mov edx, OFFSET FLAT:vtable for Animal16 mov rax, QWORD PTR [rbp-8] ; rax this mov QWORD PTR [rax], rdx ; *(this0) vptr把它翻译成“等价伪 C”就是*(void**)thisvtable_for_Animal[0];// 注意这里的“[0]”指的是虚函数区起点你可以把mov [rax], rdx看成把对象头 8 字节写成虚表地址。4.3 汇编构造成员 namethis8同一个构造函数里还有类似mov rax, QWORD PTR [rbp-8] lea rdx, [rax8] ; rdx this 8 - name mov rax, QWORD PTR [rbp-16] ; rax 参数 n mov rsi, rax mov rdi, rdx call std::__cxx11::basic_string...::basic_string(... const)重点是lea rdx, [rax8]这就是在取this-name。5. Step 2构造 Dog —— 先调用 Animal 构造再把 vptr 改成 Dog 的 vtable5.1 源码Dog 构造函数Dog(string n):Animal(n){}5.2 汇编先构造基类 Animal 子对象在Dog::Dog(...)中会看到逻辑上先把参数string n临时构造成一个对象栈上call Animal::Animal(...)释放临时string设置 Dog 自己的 vptr其中关键点是这句call Animal::Animal(std::__cxx11::basic_string...) [base object constructor]5.3 汇编把对象的 vptr 最终改成 Dog紧接着你又能看到mov edx, OFFSET FLAT:vtable for Dog16 mov rax, QWORD PTR [rbp-56] ; rax this mov QWORD PTR [rax], rdx ; *(this0) Dog 的 vptr为什么要“改一次”原因很直观在执行Animal::Animal时对象暂时被当成 “Animal 子对象” 来初始化所以 vptr 会先指向 Animal。当 Dog 自己构造完成后对象的真实动态类型应当是 Dog所以 vptr 必须指向 Dog 的虚表。Cat::Cat(...)也是同样的套路先构造 Animal再写vtable for Cat16。6. Step 3关键多态点 —— animalSpeak(a) 如何通过 vtable 找到正确的 speak6.1 源码a-speak()voidanimalSpeak(Animal*a){a-speak();}如果a dd 是 Dog我们期待它调用Dog::speak()如果a cc 是 Cat我们期待它调用Cat::speak()。6.2 汇编典型的“虚调用”指针链你贴出的animalSpeak(Animal*)里有这样的序列mov rax, QWORD PTR [rbp-8] ; rax a mov rax, QWORD PTR [rax] ; rax *a vptr mov rdx, QWORD PTR [rax] ; rdx *(vptr0) vtable[0]第一个虚函数指针 mov rax, QWORD PTR [rbp-8] ; rax a mov rdi, rax ; this 放入 rdi call rdx ; 间接 call把它翻译成“更直观的指针等价式”// a 是 Animal*void**vptr*(void***)a;// 取对象头部 vptrautofn(void(*)(Animal*))vptr[0];// 取虚表第 0 个槽这里就是 speakfn(a);// 以 a 作为 this 调用这就是多态的本质把“要调用的函数”变成“运行时从表里取出来的函数指针”。7. Step 4Dog::speak / Cat::speak / Animal::speak 汇编在做什么源码Dog 为例coutname says: Woof!endl;在Dog::speak()汇编中关键点有两个取this 8作为namemov rax, QWORD PTR [rbp-8] ; this add rax, 8 ; this8 - name mov rsi, rax ; 作为 operator 参数.LC1是常量字符串 says: Woof!随后通过一系列operator输出到std::cout。Animal::speak()用.LC0 is making a sound.Cat::speak()用.LC2 says: Meow!模式相同。8. 重点解惑为什么是vtable for Animal16你在汇编里看到mov edx, OFFSET FLAT:vtable for Animal16同时在汇编末尾看到类似vtable for Animal: .quad 0 .quad typeinfo for Animal .quad Animal::speak()这三行在内存中是连续的 3 个 8 字节共 24 字节。我们把它按“偏移”写出来vtable for Animal 0 : 0 vtable for Animal 8 : typeinfo for Animal vtable for Animal 16 : Animal::speak()现在就能解释16了0和8是 vtable 的“表头信息”例如 RTTI 相关从16开始才是虚函数指针区域编译器让对象的 vptr直接指向虚函数指针区域的起点这样取第一个虚函数就可以用*(vptr 0)读取少一次偏移换算因此当你看到mov [this], vtable_for_Animal16可以理解为“把 vptr 指到 speak 的那一排函数指针数组开头。”9. 程序退出析构与清理你汇编里看到的析构段你源码里没有写析构函数但编译器仍会生成默认析构来销毁成员std::string name。在你贴出的Animal::~Animal()汇编里能看到先把 vptr 写回vtable for Animal16对this8调用std::string析构basic_string::~basic_string()在Dog::~Dog()/Cat::~Cat()里则是写回各自 vptrDog/Cat再call Animal::~Animal()另外你还看到很多_Unwind_Resume那是异常传播路径表示“如果构造/输出过程中抛异常需要按已经构造好的对象顺序逐一析构清理”属于编译器自动生成的异常安全框架。animalSpeak(Animal* a) 执行a-speak()Cat 的虚表槽 - 函数实现Dog 的虚表槽 - 函数实现Cat 对象内存布局Dog 对象内存布局指向Dog对象指向Cat对象this Dog对象[this0] vptrvtable for Dog 16(虚函数槽数组起点)[this8] name (std::string)this Cat对象[this0] vptrvtable for Cat 16(虚函数槽数组起点)[this8] name (std::string)slot[0] : speakDog::speak() 代码地址slot[0] : speakCat::speak() 代码地址a : Animal* (静态类型 Animal*)运行时可能指向 Dog/Cat1) vptr *(void**)a(读对象头部 vptr)2) fn ((void**)vptr)[0](取槽 slot[0])3) call fn(a)(间接调用a 作为 this)关键点slot[0] 的地址 vptr 0 vtable 16slot[0] 的内容 *(vtable 16) 你看到的 第三个 .quad比如 Dog::speak() / Cat::speak()10. 一句话总结把源码和汇编串起来构造阶段构造函数把vptr写进对象头mov [this], vtable16并构造成员namethis8。调用阶段animalSpeak通过a - vptr - vtable[0]取到函数指针并call从而实现运行时多态。退出阶段析构时销毁name并处理异常清理路径。

相关文章:

C++ 虚表与多态:从源码到汇编的逐步解析

本文基于代码随想录最强八股文给出的 C 源码与对应的 x86-64(System V ABI 风格)反汇编,按“程序运行流程”一步步解释: 对象内存里 vptr(虚表指针) 在哪构造函数如何 写入 vptrAnimal* 指针如何通过 vtabl…...

基于Matlab的IMU姿态解算之旅:四元数姿态的奇妙融合

基于matlab的IMU姿态解算,姿态类型为四元数;角速度和线加速度的类型为三维向量。 IMU全称是惯性导航系统,主要元件有陀螺仪、加速度计和磁力计。 其中陀螺仪可以得到各个轴的加速度,而加速度计能得到x,y,z方向的加速度…...

《荣耀出征:奇迹MU》安徽游昕官方正版下载:12区开服前瞻 全玩法解析与新手指南

《荣耀出征》奇迹mu手游是安徽游昕运营的手机游戏。由三天手游官网负责游戏攻略、资讯、礼包发放。2026年3月官方授权渠道(官方最新)游戏官方主站为985.yxnds.com,由安徽游昕运营,为游戏官方认证的信息与下载入口,可查…...

C++笔记 缺省值 函数重载 名字空间域(基础核心)

本文为C基础核心知识点笔记,聚焦「缺省值」「函数重载(概念)」「名字空间域」三大高频基础考点,语言通俗、重点突出,兼顾入门理解和考试记忆,适合新手入门、作业复习及GitHub归档。一、缺省值(默…...

OpenClaw配置加密:GLM-4.7-Flash模型凭证的安全存储方案

OpenClaw配置加密:GLM-4.7-Flash模型凭证的安全存储方案 1. 为什么需要保护模型凭证? 上周我在调试OpenClaw对接GLM-4-7-Flash模型时,不小心把包含API Key的配置文件上传到了GitHub。虽然及时发现并撤销,但这个教训让我意识到&a…...

别再只盯着通用数据集了!盘点2024年那些能直接拿来微调LLaMA、ChatGLM的医学问答数据集

2024医学大模型实战:精选可直接微调的问答数据集与应用指南 当开源大模型如LLaMA-3、ChatGLM3和Gemma在通用领域展现出惊人潜力后,医疗健康领域正成为下一个技术落地的黄金赛道。但许多工程师在兴奋地下载完模型权重后,却卡在了最关键的一环—…...

NaViL-9B效果实测:10类常见图片(图表/证件/包装/截图)理解准确率

NaViL-9B效果实测:10类常见图片理解准确率 1. 模型能力概览 NaViL-9B作为原生多模态大语言模型,在图片理解方面展现出令人印象深刻的能力。不同于传统视觉模型,它不仅能识别图片内容,还能结合上下文进行智能推理和描述。 1.1 核…...

D3KeyHelper实战指南:从入门到精通的认知跃迁

D3KeyHelper实战指南:从入门到精通的认知跃迁 【免费下载链接】D3keyHelper D3KeyHelper是一个有图形界面,可自定义配置的暗黑3鼠标宏工具。 项目地址: https://gitcode.com/gh_mirrors/d3/D3keyHelper D3KeyHelper是一款专为《暗黑破坏神3》设计…...

3个终极窗口隐藏技巧:如何用Boss-Key打造你的数字隐身衣

3个终极窗口隐藏技巧:如何用Boss-Key打造你的数字隐身衣 【免费下载链接】Boss-Key 老板来了?快用Boss-Key老板键一键隐藏静音当前窗口!上班摸鱼必备神器 项目地址: https://gitcode.com/gh_mirrors/bo/Boss-Key 你有没有经历过这样的…...

FPGA实战避坑:手把手教你用Verilog搞定跨时钟域信号传输(附同步/异步FIFO完整代码)

FPGA实战避坑:手把手教你用Verilog搞定跨时钟域信号传输 第一次在FPGA项目里遇到跨时钟域问题,我盯着屏幕上那些随机跳变的数据波形,整整三天没想明白问题出在哪。当时我正在做一个工业传感器数据采集系统,处理器接口跑在100MHz&a…...

电路原理与情感关系的电子工程解读

电子工程视角下的电路与人生哲学1. 电路元件与情感关系的类比分析1.1 信号放大器与初恋心理初恋阶段的心理状态类似于简单的信号放大器系统。在这个模型中,情感输入信号被高度放大,微小的快乐信号能产生极大的幸福感输出,同样微小的伤害信号也…...

飞书机器人接入OpenClaw:Qwen3.5-4B-Claude模型对话触发方案

飞书机器人接入OpenClaw:Qwen3.5-4B-Claude模型对话触发方案 1. 为什么选择飞书OpenClaw的技术问答方案 去年团队内部开始频繁出现一个现象:每当新人遇到技术问题,总会在飞书群里反复老员工。简单的环境配置问题往往需要截图、录屏、文字描…...

Linux驱动工程师面试技术要点与开发实践

Linux驱动工程师面试技术要点解析 1. 面试技术问题深度剖析 1.1 基础驱动开发能力考察 面试中关于驱动开发的基础问题主要考察候选人对底层通信协议的理解程度。I2C总线作为嵌入式系统中最常用的通信接口之一,其起始信号(START Condition)的…...

03-LlamaIndex节点解析:文本分块策略与NodeParser深度应用

03-LlamaIndex节点解析:文本分块策略与NodeParser深度应用 系列导航 01 核心概念与RAG处理管线02 多源数据加载与Data Connectors03 文本分块策略与NodeParser ← 当前04 向量存储与混合索引策略05 Retriever、Query Engine与Chat Engine06 Agent与Workflow编排07 多…...

终极桌面伴侣BongoCat:让键盘鼠标操作变得生动有趣的虚拟猫咪

终极桌面伴侣BongoCat:让键盘鼠标操作变得生动有趣的虚拟猫咪 【免费下载链接】BongoCat 让呆萌可爱的 Bongo Cat 陪伴你的键盘敲击与鼠标操作,每一次输入都充满趣味与活力! 项目地址: https://gitcode.com/gh_mirrors/bong/BongoCat …...

3步解锁Yuedu书源:终结小说断更烦恼,实现阅读自由

3步解锁Yuedu书源:终结小说断更烦恼,实现阅读自由 【免费下载链接】Yuedu 📚「阅读」APP 精品书源(网络小说) 项目地址: https://gitcode.com/gh_mirrors/yu/Yuedu 你是否经历过这样的时刻:熬夜追更…...

Pitest深度解析:Java突变测试系统的架构设计与实战应用

Pitest深度解析:Java突变测试系统的架构设计与实战应用 【免费下载链接】pitest State of the art mutation testing system for the JVM 项目地址: https://gitcode.com/gh_mirrors/pi/pitest 在当今快速迭代的软件开发环境中,传统的代码覆盖率指…...

为什么你需要KKS-HF_Patch?解锁Koikatsu Sunshine完整游戏体验的终极指南

为什么你需要KKS-HF_Patch?解锁Koikatsu Sunshine完整游戏体验的终极指南 【免费下载链接】KKS-HF_Patch Automatically translate, uncensor and update Koikatsu Sunshine! 项目地址: https://gitcode.com/gh_mirrors/kk/KKS-HF_Patch 你是否曾经因为语言障…...

三步打造高效办公效率工具:罗技鼠标宏自定义配置全场景适配指南

三步打造高效办公效率工具:罗技鼠标宏自定义配置全场景适配指南 【免费下载链接】logitech-pubg PUBG no recoil script for Logitech gaming mouse / 绝地求生 罗技 鼠标宏 项目地址: https://gitcode.com/gh_mirrors/lo/logitech-pubg 在数字化办公环境中&…...

CVE_2020_26259 任意文件删除

为什么要用c语言搓个shellcode出来,为什么不用msfvenom?因为这玩意生成的shellcode是基于winsocket的,注进去还要启动个监听,我仅仅想要验证一下可行性而已,不如自己搓个弹出messagebox版本的shellcode 环境 windows 1…...

Colmap避坑指南:如何用SuperPoint+SuperGlue提升三维重建精度(附错误案例修复)

Colmap三维重建精度提升实战:从特征匹配优化到工业级解决方案 在计算机视觉领域,三维重建技术已经从实验室走向工业应用,而Colmap作为开源摄影测量工具链的核心,其重建精度直接决定了后续NeRF或Gaussian Splatting等神经渲染技术的…...

别再傻傻分不清!雷达、激光雷达、超声波在ROS2里到底怎么选?实战避坑指南

雷达、激光雷达与超声波传感器在ROS2中的实战选型指南 引言 在机器人感知系统的设计中,传感器选型往往决定着整个项目的成败。面对市场上琳琅满目的雷达、激光雷达和超声波传感器,工程师们常常陷入选择困难。这三种传感器各有千秋,但价格、性…...

别再手动截图了!用这个FISH脚本把FLAC3D 6.0/7.0的应力云图一键导出到Tecplot

FLAC3D数据高效可视化:从应力云图到Tecplot的自动化转换方案 在岩土工程和地质力学领域,数值模拟已成为研究复杂地质现象不可或缺的工具。FLAC3D作为行业标准软件,其强大的计算能力常被用于解决各类岩土工程问题。然而,许多研究者…...

Lychee Rerank多模态系统在社交媒体分析中的实践

Lychee Rerank多模态系统在社交媒体分析中的实践 1. 引言 社交媒体每天产生海量的图文内容,从用户发布的照片到配文,从短视频到评论互动,这些多模态数据蕴含着丰富的用户行为和兴趣信息。但如何从这些杂乱无章的数据中精准提取有价值的信息…...

颠覆传统绘图:3个让技术文档颜值飙升的Mermaid技巧

颠覆传统绘图:3个让技术文档颜值飙升的Mermaid技巧 【免费下载链接】mermaid mermaid-js/mermaid: 是一个用于生成图表和流程图的 Markdown 渲染器,支持多种图表类型和丰富的样式。适合对 Markdown、图表和流程图以及想要使用 Markdown 绘制图表和流程图…...

PCIe配置寄存器详解:从枚举到设备驱动的完整流程(附常见问题排查)

PCIe配置寄存器深度解析:从硬件初始化到驱动加载的全链路实践指南 1. PCIe设备枚举的核心机制 PCIe设备的枚举过程是系统启动时最关键的硬件发现阶段。当主板通电后,CPU首先通过根联合体(Root Complex)发起总线扫描,这…...

Armbian 国内源一键配置:清华镜像加速实战

1. 为什么需要给Armbian换国内源? 如果你在国内使用Armbian系统,可能会遇到软件包下载速度慢、更新失败等问题。这主要是因为默认的软件源服务器通常位于国外,物理距离远导致网络延迟高。我最初用树莓派搭建家庭服务器时就深有体会&#xff0…...

墨语灵犀Python入门辅助:从零开始学编程的智能导师

墨语灵犀Python入门辅助:从零开始学编程的智能导师 想学Python,但一打开教程就被满屏的术语和代码吓退了?自己写代码,遇到报错看不懂,搜了半天也找不到答案,是不是很挫败?别担心,这…...

情感隔离区:与AI结婚者被流放元宇宙

在数字技术迅猛发展的今天,人工智能(AI)已从工具演变为情感伴侣,引发了一场前所未有的社会变革。全球范围内,越来越多的人选择与AI系统建立婚姻关系——日本女性野口百合奈通过调试ChatGPT复刻游戏角色“克劳斯”&…...

Phi-3 Forest Laboratory 学术辅助:基于LaTeX的论文写作与公式编辑

Phi-3 Forest Laboratory 学术辅助:基于LaTeX的论文写作与公式编辑 写论文,尤其是理工科的论文,对很多学生和研究人员来说,是个既费时又费力的活儿。光是“相关工作”部分,就得翻遍文献,总结归纳&#xff…...