C++ 多态:概念,定义及实现以及原理
目录一.多态的概念1.1静多态1.2动多态重点二.多态的定义及实现2.1 多态的构成条件2.1.1 虚函数2.1.2 实现多态还有两个必须重要条件2.1.3 虚函数的重写/覆盖2.1.4 多态场景的一个选择题腾讯面试题2.1.5 虚函数重写的一些其他问题2.1.6override和final关键字2.1.7重载/重写/隐藏的对比面试考点一.多态的概念多态polymorphism的概念通俗来说就是多种形态。多态分为编译时多态静态多态和运行时多态动态多态这里我们重点讲运行时多态编译时多态静态多态和运行时多态动态多态。编译时多态静态多态主要就是我前面文章讲的函数重载和函数模板他们传不同类型的参数就可以调用不同的函数通过参数不同达到多种形态之所以叫编译时多态是因为他们实参传给形参的参数匹配是在编译时完成的我们把编译时一般归为静态运行时归为动态。运行时多态具体点就是去完成某个行为函数可以传不同的对象就会完成不同的行为就达到多种形态。比如买票这个行为当普通人买票时是全价买票学生买票时是优惠买票5折或75折)军人买票时是优先买票。再比如同样是动物叫的一个行为函数传猫对象过去就是”( ^ w ^ 喵“传狗对象过去就是”汪汪”。1.1静多态1. 核心定义在代码编译阶段编译器就已经确定好了要执行哪一个函数地址在编译期绑定也叫静态绑定、早绑定。 程序还没运行调用关系就已经敲定。2. 实现方式函数重载最典型 同一个作用域内函数名一致参数列表个数、类型、顺序不同编译器依靠参数区分调用哪个函数。运算符重载C3. 特点绑定时机编译期执行效率高运行时无额外开销不依赖继承、重写仅依靠函数签名区分。1.2动多态重点1. 核心定义编译阶段无法确定具体调用哪个函数必须等到程序运行起来根据当前对象的真实类型动态匹配对应的函数又称动态绑定、晚绑定。 也是面向对象里大家常说的狭义上的 “多态”。2. 必备条件C/Java 通用逻辑父子类存在继承关系父类声明虚函数C/ 允许重写Java子类重写父类的虚函数使用父类指针 / 引用指向子类对象。3. 特点绑定时机运行期需要继承 重写 虚函数支撑运行时有查表开销效率略低于静态多态同一个调用语句传入不同子类对象表现不同行为是多态最核心价值。对比项静态多态动态多态绑定时机编译期运行期别称早绑定、静态绑定晚绑定、动态绑定实现手段函数重载、运算符重载继承 虚函数重写、父类引用 / 指针是否需要继承不需要必须依靠继承体系运行开销几乎无开销虚表查找轻微运行开销典型场景同一类中同名不同参函数调用统一父类接口不同子类差异化实现二.多态的定义及实现2.1 多态的构成条件多态是一个继承关系的下的类对象去调用同一函数产生了不同的行为。比如Student继承了Person。Person对象买票全价Student对象优惠买票2.1.1 虚函数类成员函数前面加virtual修饰那么这个成员函数被称为虚函数。注意非成员函数不能加virtual修饰注意虚函数和虚继承虽然用的是同一个关键字virtual但是并没有什么关联关系对比维度虚函数 virtual 函数虚继承 virtual 继承修饰对象类的成员函数继承方式父类继承核心目标实现运行时多态动态绑定函数解决菱形多重继承的数据二义性、多份基类副本依赖场景单继承、普通继承都能用仅限多重菱形继承场景底层结构虚函数表 vtable 虚指针 vptr虚基表 虚基指针 vbptr作用对象控制成员函数调用逻辑调整对象内存布局、共享基类成员变量是否影响数据存储不改变成员变量布局大幅改变继承体系的内存布局典型问题解决父类指针精准调用子类重写方法d.A::x分不清是 B 里的 A 还是 C 里的 A内存开销对象增加 1 个 vptr 指针子类增加 vbptr 虚基指针2.1.2 实现多态还有两个必须重要条件被调用的函数必须是虚函数并且完成了虚函数重写/覆盖若父类没有用虚函数则不会构成多态调用的时候只会调用父类基类不开virtual编译时认准指针类型是Animal*固定调用父类方法基类开启virtual运行时查看指针指向的真实对象类型自动匹配子类重写的函数。func(a)→ Animal::talkfunc(c)→ 依然 Animal::talkfunc(d)→ 依然 Animal::talk必须是基类的指针或者引用调用虚函数2.1.3 虚函数的重写/覆盖虚函数的重写/覆盖派生类中有一个跟基类完全相同的虚函数即派生类虚函数与基类虚函数的返回值、函数名字、参数列表完全相同称派生类的虚函数重写了基类的虚函数注意在重写基类虚函数时派生类的虚函数在不加virtual关键字时虽然也可以构成重写因为C 规定基类中被virtual修饰的成员函数其 “虚函数” 的特性会被派生类继承。只要派生类定义的函数与基类虚函数的签名完全一致函数名、参数列表、const/volatile修饰符、返回类型都匹配那么这个派生类函数会自动成为虚函数无需显式加virtual关键字自然也能构成对基类虚函数的重写但是该种写法不是很规范不建议这样使用不过在考试选择题中经常会故意留这个坑让你判断是否构成多态主包之前在腾讯的笔试题中见过非常恶心只能说相关出题人用心险恶。2.1.4 多态场景的一个选择题腾讯面试题代码分析#include iostream using namespace std; // 父类基类A class A { public: // 虚函数func允许子类重写默认参数val1静态绑定的关键 virtual void func(int val 1) { cout A- val endl; } // 虚函数test内部调用func()B未重写此方法继承复用的关键 virtual void test() { func(); // 等价于 this-func()this是隐藏指针 } }; // 子类派生类Bpublic继承A继承的核心 class B : public A { public: // 重写overrideA的虚函数func函数签名和父类一致多态的前提 // 默认参数改为val0但默认参数不参与多态 void func(int val 0) { cout B- val endl; } // 关键B没有重写test() → 完全继承A的test()逻辑 }; int main() { B* p new B; // 静态类型B*动态类型B* p-test(); // 核心调用1重点分析 p-func(); // 核心调用2对比分析 delete p; // 补充避免内存泄漏 return 0; }2.1.5 虚函数重写的一些其他问题协变了解派生类重写基类虚函数时与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指针或者引用派生类虚函数返回派生类对象的指针或引用时称为协变。协变的实际意义并不大所以了解一下即可但是若AB类没有继承关系就会有报错就是因为没有满足协变的要求如下图析构函数的重写笔试常见基类的析构函数为虚函数此时派生类析构函数只要定义无论是否加 virtual 关键字都与基类的析构函数构成重写虽然基类与派生类析构函数名字不同看起来不符合重写的规则实际上编译器对析构函数的名称做了特殊处理编译后析构函数的名称统一处理成 destructor 所以基类的析构函数加了 virtual 修饰派生类的析构函数就构成重写。下面结合代码说明一下某些情况下若析构函数不加 virtual 会出现的问题为什么基类中的析构函数建议设计为虚函数这个问题在面试中经常考察一定要结合样例才可以讲清楚总结基类和派生类的析构函数在编译器的作用下定义为相同的名称在main函数中如果用基类的指针或引用来指向基类或派生类对象时若调用delete则只会调用基类的析构不会调用派生类的析构所以我们要加上virtual来构成多态指向谁调用谁这里为什么调用两次~Person1.Person* p1 new Person; delete p1;真实对象就是Person虚析构触发自身析构函数仅执行~Person()→ 控制台第一行输出~Person()2.Person* p2 new Student; delete p2;因为基类Person析构加了virtual虚析构开启动态绑定完整的析构流程运行时识别真实类型是Student优先调用子类析构~Student()C 语法强制规则子类析构执行完毕后编译器会自动调用直接父类的析构函数不需要手动写代码 → 依次打印~Student()~Person()合在一起三行输出视觉上看到两次~Person()。2.1.6override和final关键字从上面可以看出C对虚函数重写的要求比较严格但是有些情况下由于疏忽比如函数名写错参数写错等导致无法构成重写而这种错误在编译期间是不会报出的只有在程序运行时没有得到预期结果才来debug灰得不偿失因此C11提供了 override 可以帮助用户检测是否重写。如果我们不想让派生类重写这个虚函数那么可以用final修饰一、override关键字1、作用显式声明当前函数意图重写父类的虚函数编译器强制校验 必须确实正确重写了基类的虚函数否则直接编译报错杜绝手误导致 “本该重写实际变成新建重载 / 隐藏函数”。2、使用规则只能写在子类重写虚函数的形参列表末尾只能修饰成员函数不能修饰普通函数、构造 / 析构、变量基类必须是virtual虚函数否则加override编译报错。这里我们可以看出不加override编译器不会报错当我们加上override后直接就会检查出来二.final关键字2.1.7重载/重写/隐藏的对比面试考点

相关新闻

UE Niagara条带渲染器实现动态运动轨迹:从数据驱动到视觉叙事

UE Niagara条带渲染器实现动态运动轨迹:从数据驱动到视觉叙事

1. 项目概述:从静态拖尾到动态轨迹的进化 在游戏和实时视效开发里,给角色添加运动轨迹或拖尾效果,是提升动态表现力和视觉反馈的经典手法。过去,我们可能依赖材质动画、后期处理或者简单的粒子发射器来模拟,但这些方法…

2026/10/18 1:20:41 阅读更多 →
从资质扫描件到 Excel:采购建供应商准入台账的第一步

从资质扫描件到 Excel:采购建供应商准入台账的第一步

采购要把一批资质扫描件整理进 Excel 时,最容易直接跳到“先识别一下”。但真正决定结果能不能交接的,往往是更前面的动作:先说清楚每一列要记录什么、从页面哪里取、看不清时怎么留痕。 所以,建供应商准入台账的第一步不是让扫描…

2026/10/18 1:21:17 阅读更多 →
STM32串口通信实战:从原理到DMA应用与调试技巧

STM32串口通信实战:从原理到DMA应用与调试技巧

1. 项目概述:从零上手STM32串口通信 搞嵌入式开发,尤其是玩STM32的,串口通信绝对是绕不开的第一个“硬骨头”。它不像点个LED灯那么简单,但又是后续所有复杂通信(比如网络、蓝牙)的基础。很多新手&#xff…

2026/10/18 1:21:26 阅读更多 →

最新新闻

BrowserSkill:基于Chrome DevTools Protocol的轻量级浏览器CLI自动化工具

BrowserSkill:基于Chrome DevTools Protocol的轻量级浏览器CLI自动化工具

1. 项目概述:BrowserSkill不是插件,而是一套浏览器自动化能力的CLI封装体系BrowserSkill这个词最近在开发者社区里频繁出现,但它既不是Chrome商店里某个新上架的视频下载插件,也不是Edge浏览器内置的Copilot功能升级包。我第一次在…

2026/10/18 19:24:21 阅读更多 →
新能源汽车数据集源码解析:从标注转换到训练落地全攻略

新能源汽车数据集源码解析:从标注转换到训练落地全攻略

简介:面向人工智能与新能源交叉领域研究者的数据索引型源码包,围绕新能源汽车健康度、充电站运营、充电桩布设、充电需求时空、电池异常检测、公交驾驶、车牌识别等八个细分方向,整理并说明了各数据集的数据背景、应用领域、目录结构及用途&a…

2026/10/18 19:24:21 阅读更多 →
充电桩平台源码解析:国标协议解耦与高并发状态同步

充电桩平台源码解析:国标协议解耦与高并发状态同步

简介:这是一套面向Java开发者与新能源智能充电系统学习者的完整充电桩平台源码资源,聚焦于云快充协议对接、多租户运营及分时计费等核心业务场景,助力快速构建可商用的充电管理SaaS系统。资源包共13个文件,含10个Java核心类&#…

2026/10/18 19:24:21 阅读更多 →
Agent Skills实战:从工具调用到技能化智能体开发指南

Agent Skills实战:从工具调用到技能化智能体开发指南

做AI应用这两年,我踩过一个很大的坑:给大模型接了一堆工具,结果它真正跑起来的时候,反而不知道什么时候该用哪一个,经常在无关的工具之间来回横跳。后来我把整套交互方式改成了Agent Skills——把每一个工具变成一份带…

2026/10/18 19:24:21 阅读更多 →
Octop:Python依赖治理CLI工具,解决包名漂移与环境不可复现问题

Octop:Python依赖治理CLI工具,解决包名漂移与环境不可复现问题

1. 项目概述:Octop 是什么?它解决的不是“安装 Python”这个表层问题Octop 这个名字乍看像某个开源工具、库名,甚至有人会联想到章鱼(octopus)——毕竟“octo-”前缀在技术圈里常暗示“八路”“多线程”“分布式”或“…

2026/10/18 19:24:21 阅读更多 →
从需求拆解到部署:基于深度学习的口罩识别系统实战

从需求拆解到部署:基于深度学习的口罩识别系统实战

口罩识别这种项目,这几年几乎成了目标检测入门的标准练手题。但说实话,真正把它做成一个能稳定跑的落地系统,和跑通一个开源notebook之间的差距,比很多人想象得大得多。这篇文章就从我实际做完一个基于深度学习的口罩识别系统出发…

2026/10/18 19:23:20 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →