详细介绍:c++ 之多态虚函数表

news/2025/10/2 13:14:41/文章来源:https://www.cnblogs.com/ljbguanli/p/19123501

详细介绍:c++ 之多态虚函数表

你这个问题触及了 C++ 多态的核心机制——非常棒!
你的理解已经非常接近真相,但其中有些细节需要澄清和精确化。我们一步步来梳理:


✅ 一、先回答你的核心问题:

“函数参数是基类引用,为什么能绑定到子类对象?是因为虚函数表吗?”

是的,但更准确地说:

  • 引用(或指针)能绑定到子类对象,是因为 C++ 的类型兼容规则(派生类 → 基类 是隐式转换)
  • 而调用时能正确执行子类版本的函数,才真正依赖虚函数表(vtable)机制

这两个是不同阶段的事情:

阶段机制说明
1. 绑定/传参类型兼容性(is-a 关系)子类对象可以隐式转换为基类引用/指针
2. 函数调用虚函数表(vtable) + 动态分派运行时根据对象实际类型调用正确函数

二、详细拆解

1️⃣ 为什么基类引用能绑定子类对象?

void func(Animal& a);  // 参数是基类引用
Dog dog;
func(dog);  // ✅ 合法!

这是因为 C++ 规定:派生类对象可以隐式转换为 public 基类的引用或指针(“is-a”关系)。

这一步和虚函数无关!即使没有虚函数,也能传参成功。

class Base {};
class Derived : public Base {};
void f(Base& b) {}
Derived d;
f(d); // ✅ 编译通过,即使没有虚函数

所以:引用能“指向”子类,是语言的类型系统允许的,不是因为 vtable。


2️⃣ 那虚函数表(vtable)起什么作用?

vtable 的作用是:在运行时,让基类指针/引用调用正确的子类函数版本。

内存布局示意(简化):
class Animal {
public:virtual void speak() { cout << "??"; }virtual ~Animal() = default;
};
class Dog : public Animal {
public:void speak() override { cout << "Woof!"; }
};

每个 有虚函数的类 会有一个 vtable(虚函数表),每个 对象 会有一个 vptr(虚表指针),指向其所属类的 vtable。

Dog 对象内存布局:
┌──────────────┐
│ vptr ────────┼──→ [ Dog 的 vtable ]
├──────────────┤     ├── speak → Dog::speak
│ 其他成员...   │     └── ~Animal → Dog::~Dog
└──────────────┘

子类不会“修改”基类的 vtable,而是拥有自己独立的 vtable,其中:

  • 覆盖的虚函数 → 指向子类实现
  • 未覆盖的虚函数 → 指向基类实现

3️⃣ 调用过程(关键!)

Animal& a = dog;  // 静态类型:Animal&,动态类型:Dog
a.speak();        // 如何调用到 Dog::speak()?

编译器生成的伪代码类似:

// a.speak() 实际变成:
(a.__vptr[0])(&a);  // 通过对象的 vptr 找到第一个虚函数(speak),然后调用
  • a 的静态类型是 Animal&,所以编译器知道 speak 是虚函数(查 Animal 的声明)
  • 但运行时,a 实际引用的是 Dog 对象,它的 __vptr 指向 Dog 的 vtable
  • 所以调用了 Dog::speak

这就是“动态绑定”(dynamic binding)或“运行时多态”


❌ 三、纠正一个误解

你说:

“子类会修改基类的虚函数表,会共用这一张表”

这是不准确的。

正确理解是:

说法正确性说明
子类修改基类的 vtable基类的 vtable 是只读的、全局的,不会被修改
子类和基类共用一张 vtable每个有虚函数的类都有自己的 vtable
子类 vtable 继承基类 vtable 内容✅(概念上)子类 vtable 初始拷贝基类 vtable,然后覆盖被重写的函数指针

例如:

Animal vtable:[0] → Animal::speak[1] → Animal::~Animal
Dog vtable:[0] → Dog::speak      ← 被 override 的函数[1] → Dog::~Dog       ← 析构函数也重写(应为虚)

每个对象的 vptr 指向其“实际类型”的 vtable,不是基类的。


四、静态类型 vs 动态类型

概念说明示例
静态类型(Static Type)编译时已知的类型(变量声明的类型)Animal& a → 静态类型是 Animal
动态类型(Dynamic Type)运行时对象的实际类型a 引用的是 Dog 对象 → 动态类型是 Dog
  • 非虚函数调用:按静态类型解析(编译时绑定)
  • 虚函数调用:按动态类型解析(运行时通过 vtable 绑定)

✅ 五、总结:回答你的原始疑问

你的疑问正确解释
“基类引用为什么能指向子类?”因为 C++ 允许派生类 → 基类的隐式转换(类型兼容),与虚函数无关
“是因为虚函数表吗?”绑定(传参)不需要 vtable;但多态调用需要 vtable
“子类修改基类 vtable?”❌ 子类有自己的 vtable,不修改基类的
“共用一张表?”❌ 每个类有自己的 vtable,子类 vtable 覆盖了重写的函数项
“基类指针如何找到子类函数?”通过对象内部的 vptr → 指向子类 vtable → 找到子类函数地址

最后一句话:

“引用/指针能绑定子类,靠的是类型系统;
调用时能执行子类函数,靠的是虚函数表。”

你已经抓住了多态的本质,现在这些细节的澄清会让你的理解更加坚实!
继续这样深入思考,你会成为 C++ 的高手!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/924933.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微信授权登录网站退出怎么做网站安全检测入口

[LeetCode] 485.最大连续 1 的个数(Java) 1.题目描述 力扣传送门 给定一个二进制数组 nums &#xff0c; 计算其中最大连续 1 的个数。 示例 1&#xff1a;输入&#xff1a;nums [1,1,0,1,1,1] 输出&#xff1a;3 解释&#xff1a;开头的两位和最后的三位都是连续 1 &…

建材做哪些网站买购网

目录 1&#xff1a;什么是序列化、反序列化&#xff1f; 2&#xff1a;序列化的用途&#xff1f; 3&#xff1a;序列化的n种方式 1&#xff1a;什么是序列化、反序列化&#xff1f; 把对象转换为字节序列的过程称为对象的序列化把字节序列转换为对象的过程中称为对象的反序列…

2025球墨铸铁管厂家TOP企业品牌推荐排行榜,k9球墨铸铁管,c25球墨铸铁管,c30球墨铸铁管,c级国标离心球墨铸铁管,c级供水球墨铸铁管,dn900球墨铸铁管公司推荐!

在当前城市基础设施建设与市政工程快速推进的背景下,球墨铸铁管作为供水、排水、消防等领域的关键管材,其市场需求持续增长。然而,行业发展也面临诸多问题,一方面,部分生产厂家为降低成本,在原材料选用和生产工艺…

10/2

今日学习了Java和英语,背诵了单词,明日继续

使用 VictoriaLogs 存储和查询服务器日志

欢迎访问我的个人小站 莹的网络日志 ,不定时更新文章和技术博客~目前为止,我查询服务器日志的方式都是小作坊式做法,先是连进服务器找到日志文件,要么使用 vim 打开文件搜索要么就是用 grep。当前我只有一个服务器…

详细介绍:Git 基础 - 查看提交历史

详细介绍:Git 基础 - 查看提交历史pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco…

语音合成技术

语音合成技术本博客是博主个人学习时的一些记录,不保证是为原创,个别文章加入了转载的源地址,还有个别文章是汇总网上多份资料所成,在这之中也必有疏漏未加标注处,如有侵权请与博主联系。 如果未特殊标注则为原创…

求职网站网页模板下载网站模板绑定域名

来源&#xff1a;卫星界据工业和信息化部官网10月9日消息&#xff0c;依据《工业和信息化部重点实验室管理暂行办法》&#xff08;工信部科〔2014〕515号&#xff09;&#xff0c;经评审和公示&#xff0c;工业和信息化部公布2019年工业和信息化部重点实验室名单。根据文件&…

PowerShell 提供程序和驱动器(七)

PowerShell 提供程序和驱动器目录PowerShell 提供程序和 PowerShell 驱动器PowerShell 提供程序查看提供程序的帮助文件使用PowerShell 驱动器处理 PowerShell 驱动器位置管理文件系统管理注册表获取注册表项获取注册表…

网站建设 业务员提成岳阳seo

命令模式&#xff08;Command Pattern&#xff09;是一种行为设计模式&#xff0c;它将一个请求封装为一个对象&#xff0c;从而使你可以用不同的请求对客户进行参数化&#xff0c;对请求排队或记录请求日志&#xff0c;以及支持可撤销的操作。 命令模式主要包含以下几个角色&…

用织梦做的学校网站建设工程教育网官网学员登录

OpenCV 例程200篇 总目录-202205更新 【youcans 的 OpenCV 例程200篇】180.基于距离变换的分水岭算法 【youcans 的 OpenCV 例程200篇】181.基于 Sobel 梯度的分水岭算法 【youcans 的 OpenCV 例程200篇】182.基于形态学梯度的分水岭算法 【youcans 的 OpenCV 例程200篇】183.基…

400选号网站源码wordpress聚合广告平台

让我们定义dn​为&#xff1a;dn​pn1​−pn​&#xff0c;其中pi​是第i个素数。显然有d1​1&#xff0c;且对于n>1有dn​是偶数。“素数对猜想”认为“存在无穷多对相邻且差为2的素数”。 现给定任意正整数N(<105)&#xff0c;请计算不超过N的满足猜想的素数对的个数。…

2025热熔胶厂家 TOP 企业品牌推荐排行榜,书刊装订,珍珠棉,纸箱包装,环保,书本,试卷,票据,平摊,胶版纸,铜版纸热熔胶公司推荐!

在当前热熔胶应用领域不断拓展的背景下,行业发展虽呈现蓬勃态势,但也面临着诸多亟待解决的问题。从市场层面来看,热熔胶产品质量参差不齐,部分厂家为追求短期利益,降低生产标准,导致产品出现粘性不足、易脆断、有…

cyberstrikelab-lab14

flag1 pluck 后台弱密码 cslab 第一次打的时候任意文件上传上传不上去,怀疑是没配置好 temp 目录的权限,这里用另一个漏洞 先把报错的 album 模块删掉 抓包修改 cont2 cont2=;eval($_POST[x]);//蚁剑连接 http://10.…

GreenHat 中文系列教程 2025.10 更新

10 个 LED 极客项目 20 个简单的树莓派项目 FreeBSD 绝对指南 算法思维 安卓恶意软件手册 安卓安全内部原理 面向 Arduino 爱好者的 Arduino 指南 Arduino 发明者指南 Arduino 游乐场 Arduino 项目手册 Arduino 项目手…

编译器细节:动态链接与静态链接行为分析

gcc 与ld.so (以 Alpine Linux为例)背景:Alpine Linux 是一个基于 musl libc 和 busybox 构建的轻量级 Linux 发行版,专注于安全性、资源效率和简洁性。它被广泛用于 Docker 容器、嵌入式系统和云计算环境。gcc 和…

网站图片特效源码品牌建设工作经验

前言&#xff1a;关于MVC和SSM基本内容的梳理&#xff0c;以及两者之间的关系。 文章目录 1. 三层架构2. MVC3. SSM 1. 三层架构 三层架构是指&#xff1a; 视图层view&#xff08;表现层&#xff09;: 用于显示数据和接收用户输入的数据&#xff0c;为用户提供一种交互式操作…

.net做网站用什么框架长春是几线城市2021

0. cas服务搭建参考:CAS 5.3服务器搭建_cas-overlay-CSDN博客 1. 参照springsecurity适配cas的方式, 一直失败, 无奈关闭springssecurity认证 2. 后端服务适配cas: 参考前后端分离项目(springbootvue)接入单点登录cas_前后端分离做cas单点登录-CSDN博客 1) 引入maven依赖 …

使用虚幻引擎(UE5)制作开箱爆金币功能 - 详解

使用虚幻引擎(UE5)制作开箱爆金币功能 - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", &…

网站空间内存公司建设网站带来什么

目录 前言&#xff1a; 题单&#xff1a; P3386 【模板】二分图最大匹配 P1525 [NOIP2010 提高组] 关押罪犯 P3385 【模板】负环 P3371 【模板】单源最短路径&#xff08;弱化版&#xff09; SPFA写法 Dij写法&#xff1a; P3385 【模板】负环 P5960 【模板】差分约束…