0

0

C++多态调用流程剖析_C++父类指针指向子类原理

冰川箭仙

冰川箭仙

发布时间:2025-12-31 08:55:35

|

866人浏览过

|

来源于php中文网

原创

C++多态通过虚表(vtable)和虚表指针(vptr)实现:每个含虚函数的类有唯一vtable,对象内存首部存vptr指向所属类vtable;父类指针调用虚函数时,根据实际对象的vptr动态查表跳转,而非静态类型;非虚函数编译期绑定,不进vtable;对象切片会丢失vptr,故多态仅适用于指针或引用。

c++多态调用流程剖析_c++父类指针指向子类原理

当用父类指针指向子类对象并调用虚函数时,C++不是靠类型声明决定调用哪个函数,而是靠对象实际内存中携带的虚表指针(vptr)在运行时动态查找——这就是多态的核心机制。

虚函数表(vtable)是多态的底层支撑

编译器为每个含虚函数的类生成一张虚函数表,表中按声明顺序存放该类所有虚函数的地址。子类继承父类虚表后,会用自己的虚函数地址覆盖父类对应位置(若重写了该函数)。每个对象在内存头部隐式存储一个指向其所属类虚表的指针(vptr),构造对象时由构造函数自动初始化。

  • 父类对象的 vptr 指向父类 vtable
  • 子类对象的 vptr 指向子类 vtable(即使没新增虚函数,也会有一份拷贝)
  • 虚表本身是只读数据段中的静态结构,不随对象数量变化

父类指针调用虚函数的真实流程

red">Base* p = new Derived(); p->func(); 时,编译器生成的指令不是直接跳转,而是三步查表:

  • 从 p 所指内存首地址取出 vptr(偏移量为 0)
  • 根据 func 在虚表中的索引(比如第 1 项),访问 vptr 指向的虚表 + 偏移地址
  • 取出该位置存储的函数地址,然后 call 它

整个过程不依赖 p 的静态类型 Base*,只依赖 p 实际指向的对象内存布局——所以哪怕 p 是 Base*,只要它指向的是 Derived 对象,就一定调用 Derived::func()。

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

SlidesAI
SlidesAI

使用SlidesAI的AI在几秒钟内创建演示文稿幻灯片

下载

为什么非虚函数不参与多态

非虚函数没有进入虚表,编译器在编译期就根据指针/引用的静态类型决定调用目标,生成直接 call 指令。例如 Base* p = new Derived(); p->non_virtual(); 会无条件调用 Base::non_virtual(),哪怕 Derived 里也定义了同名函数且参数一致——这叫隐藏(hiding),不是重写(overriding)。

  • 只有被 virtual 修饰、且在派生类中签名完全匹配的函数才构成重写
  • 构造函数、析构函数、static 成员函数天然不能是虚函数(除析构函数可且推荐声明为 virtual)
  • inline 和 virtual 一般不共存:虚函数需要地址以填入虚表,而 inline 是编译器优化提示,二者语义冲突

一个易忽略的关键点:对象切片与 vptr 丢失

多态只对指针和引用有效。如果写 Base b = Derived();,会发生对象切片——只复制 Base 部分,Derived 特有成员和 vptr 全部丢弃,b 的 vptr 指向 Base 的虚表,后续调用全是 Base 版本。这也是为什么多态接口必须用指针或引用传递,不能传值。

  • 函数参数写 void func(Base b) → 切片,无多态
  • 正确写法是 void func(Base& b) 或 void func(Base* b)
  • 智能指针如 std::shared_ptr 同样保留 vptr,安全支持多态

基本上就这些。理解 vptr 和 vtable 的存在与协作方式,比死记“父类指针可以调子类函数”更有价值——它让你看清 C++ 多态不是语法糖,而是有明确内存布局和运行时开销的确定机制。

相关专题

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

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

14

2025.11.27

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

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

173

2023.11.23

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

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

92

2025.11.27

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

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

989

2023.10.19

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

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

50

2025.10.17

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

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

195

2025.12.29

java值传递和引用传递有什么区别
java值传递和引用传递有什么区别

java值传递和引用传递的区别:1、基本数据类型的传递;2、对象的传递;3、修改引用指向的情况。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

106

2024.02.23

go语言引用传递
go语言引用传递

本专题整合了go语言引用传递机制,想了解更多相关内容,请阅读专题下面的文章。

156

2025.06.26

桌面文件位置介绍
桌面文件位置介绍

本专题整合了桌面文件相关教程,阅读专题下面的文章了解更多内容。

0

2025.12.30

热门下载

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

精品课程

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

共94课时 | 5.6万人学习

C 教程
C 教程

共75课时 | 3.8万人学习

C++教程
C++教程

共115课时 | 10.5万人学习

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

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