0

0

c++中虚函数如何实现多态_c++多态性底层原理【深度】

裘德小鎮的故事

裘德小鎮的故事

发布时间:2026-03-12 19:17:02

|

202人浏览过

|

来源于php中文网

原创

虚函数调用能指向子类实现是因为编译器为含虚函数的类生成虚函数表(vtable),对象隐式存储指向该表的指针(vptr),运行时通过vptr动态绑定;常见失效原因包括未声明virtual、签名不一致、构造/析构中调用、对象值调用或切片等。

c++中虚函数如何实现多态_c++多态性底层原理【深度】

虚函数调用为什么能指向子类实现

因为编译器为含虚函数的类生成了虚函数表(vtable),每个对象开头隐式存了一个指向该表的指针(vptr)。运行时通过 vptr 找到对应函数地址,不是靠类型声明决定的。

常见错误现象:Base* p = new Derived(); p->func(); 却调用了 Base::func() —— 很可能 func() 没加 virtual,或者子类函数签名不一致(比如参数 const 修饰不同、返回类型协变没满足)。

  • 必须在基类中用 virtual 显式声明,子类重写时可加可不加(C++11 起推荐加 override
  • 构造函数/析构函数不能是虚函数?错——析构函数**应该**是虚的,否则 delete base_ptr 不会调用子类析构
  • 纯虚函数写法是 virtual void func() = 0;,含纯虚函数的类不能实例化

虚函数表布局和内存开销怎么看

每个含虚函数的类只有一个 vtable(静态分配),但每个对象多占一个指针大小(通常是 8 字节)。vtable 本质是函数指针数组,顺序按虚函数声明顺序排列,子类覆写会覆盖对应槽位,新增虚函数则追加。

使用场景:调试时怀疑多态失效,可以打印对象地址和 vptr 值(如 GDB 中 p/x *(void**)obj),再查 vtable 内容验证是否指向预期函数。

立即学习C++免费学习笔记(深入)”;

  • 多重继承下,子类对象可能有多个 vptr(每个虚基类路径一个),布局更复杂
  • 空基类优化(EBO)对虚函数类无效——只要有一个虚函数,对象就不能被压缩为 0 字节
  • Clang/GCC 可用 -fdump-class-hierarchy 输出 vtable 结构,比手算靠谱

哪些情况会导致虚函数多态“失效”

不是编译器坏了,而是调用点没走动态绑定路径。最典型的是:在构造/析构函数里调用虚函数,此时对象还没完全构造好或正在销毁,vptr 指向当前正在构造/析构的那个类的 vtable。

腾讯交互翻译
腾讯交互翻译

腾讯AI Lab发布的一款AI辅助翻译产品

下载

错误示例:Base::Base() { func(); },即使 Derived 重写了 func(),这里也只会调 Base::func()

  • 直接通过对象值调用(obj.func())——走静态绑定,跟虚不虚无关
  • 函数参数是基类值类型(非引用/指针),发生对象切片,虚函数信息丢失
  • 模板函数里调用 T::func(),若 T 是具体类型而非多态接口,也不走虚调用

虚函数 vs 函数指针 vs std::function 性能差异

虚函数调用比普通函数多一次内存读(取 vptr)、一次间接跳转,现代 CPU 分支预测做得好,实际开销通常就 1–3 个周期;而 std::function 构造/拷贝成本高,std::function 调用还涉及一层封装跳转。

性能影响明显的情况:高频循环内反复调用虚函数(比如图形渲染每帧上百万次),且派生类固定——这时可考虑 CRTP 或模板策略替代。

  • 虚函数无法内联(除非编译器能确定具体类型,比如 Derived d; d.func();
  • final 关键字标记类或函数后,编译器知道无进一步覆写,可能内联或优化掉 vtable 查找
  • 避免在虚函数里做耗时操作,因为多态本意是解耦,不是性能热点

虚函数机制本身很轻量,真正容易出问题的从来不是 vtable,而是开发者误以为“写了 virtual 就万事大吉”,忽略了对象生命周期、切片、签名匹配这些硬约束。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

27

2025.11.27

java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

27

2025.11.27

c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

562

2023.09.20

javascriptvoid(o)怎么解决
javascriptvoid(o)怎么解决

javascriptvoid(o)的解决办法:1、检查语法错误;2、确保正确的执行环境;3、检查其他代码的冲突;4、使用事件委托;5、使用其他绑定方式;6、检查外部资源等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

186

2023.11.23

java中void的含义
java中void的含义

本专题整合了Java中void的相关内容,阅读专题下面的文章了解更多详细内容。

134

2025.11.27

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1926

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

656

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2395

2025.12.29

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

76

2026.03.11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 11.2万人学习

C 教程
C 教程

共75课时 | 5.4万人学习

C++教程
C++教程

共115课时 | 21.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号