C++虚函数是什么原理?C++虚函数与动态绑定详解【面试必问】


虚函数通过vptr指向vtable实现动态绑定,运行时根据对象实际类型查表调用对应函数;vtable编译期生成、类共享,vptr对象独有;纯虚函数强制子类实现,抽象类不可实例化。

虚函数的核心原理是“用一个指针(vptr)指向一张函数地址表(vtable),运行时查表调用”,它让基类指针能根据实际对象类型,自动调用对应子类的函数版本——这就是动态绑定,也是C++运行时多态的根基。

虚函数表(vtable)和虚表指针(vptr)是怎么回事

每个含虚函数的类,编译器会在编译期生成一张只读的虚函数表(vtable),里面按声明顺序存着该类所有虚函数的地址。这张表是类级别的,所有该类对象共用同一张表。

而每个该类的对象,内存布局开头会隐式插入一个指针成员(vptr),大小为4字节(32位)或8字节(64位),指向所属类的vtable。

  • vtable在编译时就确定,不会运行时生成
  • 派生类vtable会继承基类虚函数项,并把被重写的函数地址替换成自己的实现
  • 新增的虚函数追加到vtable末尾;纯虚函数对应位置存nullptr(调用会崩溃)
  • 对象的vptr永远指向“自己真实类型”的vtable,哪怕它是用基类指针接收的

动态绑定怎么发生的

当你写base_ptr->func()func()是虚函数时,编译器生成的代码实际执行三步:

  • base_ptr所指对象的首地址取出vptr
  • 通过vptr找到对应的vtable
  • 查vtable中func()所在索引(编译期已固定),取出函数地址并调用

整个过程发生在运行时,不依赖指针的声明类型,只取决于对象的实际类型。没有virtual关键字,就走静态绑定——直接按指针类型选函数,完全跳过查表。

为什么不用每个对象存一堆函数指针

早期有人想过让每个对象自己存10个虚函数指针,但问题明显:

  • 1000个对象 × 10个指针 = 至少8KB额外内存(64位下),严重浪费
  • 继承时需手动初始化所有指针,极易出错、难维护
  • 无法支持虚函数覆盖逻辑(比如子类没重写,仍要调基类实现)

vtable方案只让每个对象多占1个指针空间,复用率高、结构清晰、语义明确——这才是C++选择它的根本原因。

虚函数和纯虚函数的关键区别

虚函数有默认实现,子类可选重写;纯虚函数形如virtual void f() = 0;,它强制子类必须提供实现,否则该子类也无法实例化。

  • 含纯虚函数的类叫抽象类,不能new对象
  • 纯虚函数本质是“只定义接口,不提供实现”,用于规范派生类行为
  • 抽象类的vtable里,纯虚函数对应项通常填nullptr,首次调用会触发abort

基本上就这些。理解vptr→vtable→函数地址这条链,就抓住了虚函数机制的命脉。


# 字节  # c++  # 区别  # 为什么  # 多态  # 子类  # void  # 指针  # 继承  # 虚函数  # 纯虚函数  # 接口  #   # 指针类型  # 对象  # 绑定  # 重写  # 抽象类  # 自己的  # 派生类  # 首次  # 这就是  # 会在  # 它是 


相关栏目: 【 Google疑问12 】 【 Facebook疑问10 】 【 网络优化76771 】 【 技术知识130152 】 【 IDC云计算60162 】 【 营销推广131313 】 【 AI优化88182 】 【 百度推广37138 】 【 网站推荐60173 】 【 精选阅读31334


相关推荐: 电脑的“网络和共享中心”去哪了_Windows 11新版网络设置指南【新手】  Windows 11如何开启文件夹加密(EFS)_Windows 11文件属性中加密内容以保护数据  如何使用Golang实现微服务状态监控_Golang服务运行状态采集方法  Python类装饰器使用_元编程解析【教程】  Windows服务持续崩溃怎样修复_系统服务保护机制解析  Win11笔记本怎么看电池健康度_Win11电池报告生成命令【详解】  如何解决同一段404代码在不同主机上表现不一致的问题  Django密码修改后会话失效的解决方案  c++ stringstream用法详解_c++字符串与数字转换利器  Python代码测试策略_质量保障解析【教程】  如何在JavaScript中动态拼接PHP的base_url与前端变量  Win11怎样安装剪映专业版_Win11安装剪映教程【步骤】  Win10系统怎么查看端口状态_Windows10 CMD查看网络连接  如何在Golang中使用time处理时间_Golang time时间解析与格式化方法  Win11怎么设置任务栏对齐方式_Windows11个性化任务栏行为  Win10怎样设置闹钟贪睡时间 Win10闹钟贪睡时长设置【步骤】  Win11怎么关闭通知中心_Windows11系统通知与专注助手设置  如何在同包不同文件中正确引用 Go 结构体  C++如何将C风格字符串(char*)转换为std::string?(代码示例)  Win11如何设置ipv6 Win11开启IPv6网络协议教程【步骤】  Windows10如何更改系统字体大小_Win10辅助功能文本缩放设置  如何将竖排文本文件转换为横排字符串  Python与GPU加速技术_CUDA与Numba高性能计算实践  Go 中 defer 语句在 goroutine 内部不返回时不会执行  php8.4匿名类怎么用_php8.4匿名类创建与使用场景【介绍】  PHP 中如何在函数内持久化修改引用变量的指向  Win11怎么关闭自动维护 Win11禁用系统自动维护功能【优化】  C++ STL算法库怎么用?C++常用算法函数(sort, find)教程【效率提升】  Windows10蓝屏代码DPC_WATCHDOG_VIOLATION_Win10死机修复指南  c# Task.Yield 的作用是什么 它和Task.Delay(1)有区别吗  Mac如何备份到iCloud_Mac桌面与文稿文件夹云同步【设置】  mac怎么打开终端_MAC终端Terminal使用入门与常用命令【教程】  PowerShell怎么创建复杂的XML结构  如何使用正则表达式批量替换重复的“-”模式为固定字符串  Win10如何卸载自带Edge_Win10彻底卸载Edge浏览器教程【攻略】  静态属性修改会影响所有实例吗_php作用域操作符下静态存储【教程】  win11如何清理传递优化文件 Win11为C盘瘦身删除更新缓存【技巧】  c++ try_emplace用法_c++ map高效插入数据  Python文件操作优化_大文件与流处理解析【教程】  Win11怎么开启游戏工具栏_Windows11 Xbox Game Bar快捷键  Windows10怎么卸载预装软件_Windows10预装软件卸载步骤【教程】  Drupal 中 HTML 链接被双重转义导致渲染异常的解决方案  Win10如何关闭安全中心所有通知 Win10禁用Windows Defender提醒【设置】  如何使用Golang处理静态文件缓存_提高页面加载速度  Win11声音太小怎么办_Windows 11开启响度均衡增强音量【技巧】  Mac如何整理桌面文件_Mac使用堆栈功能一键整理  Python 中将 ISO 8601 时间戳转换为日期并计算日期差值的完整教程  Golang如何避免指针逃逸_Golang逃逸分析与堆栈优化策略  Python函数接口稳定性_版本演进解析【指导】  php485在php5.6下能用吗_php485旧版本兼容性问题说明【详解】 

 2025-12-16

了解您产品搜索量及市场趋势,制定营销计划

同行竞争及网站分析保障您的广告效果

点击免费数据支持

提交您的需求,1小时内享受我们的专业解答。

致胜网络推广营销网


致胜网络推广营销网

致胜网络推广营销网专注海外推广十年,是谷歌推广.Facebook广告全球合作伙伴,我们精英化的技术团队为企业提供谷歌海外推广+外贸网站建设+网站维护运营+Google SEO优化+社交营销为您提供一站式海外营销服务。

 915688610

 17370845950

 915688610@qq.com

Notice

We and selected third parties use cookies or similar technologies for technical purposes and, with your consent, for other purposes as specified in the cookie policy.
You can consent to the use of such technologies by closing this notice, by interacting with any link or button outside of this notice or by continuing to browse otherwise.