【C++进阶】第2课—多态

文章目录

  • 1. 认识多态
  • 2. 多态的定义和实现
    • 2.1 构成多态的必要条件
    • 2.2 虚函数
    • 2.3 虚函数的重写或覆盖
    • 2.4 协变(了解)
    • 2.5 析构函数的重写
    • 2.6 override和final关键字
    • 2.7 重载、重写、隐藏对比
  • 3. 纯虚函数和抽象类
  • 4. 多态原理
    • 4.1 虚函数表指针
    • 4.2 多态的实现
    • 4.3 静态绑定和动态绑定
    • 4.4 虚函数表

1. 认识多态

  • 通俗点讲,多态其实就是多种形态,它分为编译时多态(静态多态)和运行时多态(动态多态)
  • 编译时多态(静态多态):主要就是之前讲过的函数模版和函数重载,它们在编译阶段,通过传不同类型的参数来调用对应的函数,通过参数不同就可以达到多种形态
  • 运行时多态(动态多态):具体一点就是传不同对象就可以完成不同的行为(函数),从而达到多种形态。例如:对于买票来说,学生买票半价,普通人全价,军人优先买票。

2. 多态的定义和实现

  • 多态是一个继承关系下的类的对象,去调用同一个函数,产生了不同的行为。

在这里插入图片描述


2.1 构成多态的必要条件

  • 必须是基类的指针或引用调用虚函数
  • 被调用的函数必须是虚函数,并且完成了虚函数的重写/覆盖

2.2 虚函数

  • 简单来说,虚函数就是在类成员函数前面+关键字virtual修饰,该成员函数也被称为虚函数,注意:非成员函数不能+virtual修饰

在这里插入图片描述


2.3 虚函数的重写或覆盖

  • 虚函数的重写或覆盖:派生类中有一个跟基类完全相同的虚函数(即返回值、函数名、参数列表类型完全相同),称为派生类的虚函数重写了基类的虚函数

在这里插入图片描述


  • 关于多态,可以看下面三组对比,就明白为啥只有使用基类指针/引用调用虚函数才会实现多态的效果了

在这里插入图片描述


  • 在重写虚函数时,派生类的虚函数可以不+virtual,也可以和基类的虚函数构成重写/覆盖(基类被继承后,其虚函数的属性也被派生类继承了下来)。但是实际项目中,最好还是加上

在这里插入图片描述


  • 接下来我们看一道关于多态的选择题

在这里插入图片描述


2.4 协变(了解)

  • 派生类重写虚函数时,与基类虚函数返回值类型不同,即基类虚函数返回基类对象的指针/引用,派生类虚函数返回派生类对象的指针/引用时,称为协变。实际项目中意义不大,了解即可

在这里插入图片描述


2.5 析构函数的重写

  • 基类的析构函数为虚函数,那么派生类的析构函数无论加不加virtual修饰,都和基类的析构函数构成重写(主要是因为编译器将类的析构函数名字都特殊处理为destructor)

在这里插入图片描述


在这里插入图片描述


2.6 override和final关键字

  • 可以看出,C++对于虚函数重写要求比较高,但也有可能有些情况下就疏忽忘写,例如函数名写错,写错参数等,因此C++就提出关键字override来检查是否达到虚函数重写

在这里插入图片描述


  • 如果不想让派生类去重写虚函数,可用final修饰

在这里插入图片描述


2.7 重载、重写、隐藏对比

在这里插入图片描述


3. 纯虚函数和抽象类

  • 在虚函数的后面写上=0,则这个函数为纯虚函数,纯虚函数不需要定义实现(实现也没啥意义,因为要被派生类重写,但是语法上可以实现),只要声明即可
  • 包含纯虚函数的类叫做抽象类,抽象类不能实例化出对象
  • 如果派生类继承后不重写纯虚函数,那么派生类也是抽象类
  • 纯虚函数某种程度上强制了派生类重写虚函数,因为不重写实例化不出对象

在这里插入图片描述


4. 多态原理

4.1 虚函数表指针

在这里插入图片描述


  • 可以看出,对于含有虚函数的类,其内都有一个虚函数表指针vfptr(全称virtual function ptr),该指针指向虚函数的地址(虚函数表指针可能放在对象前面,也可能放在对象后面,具体看平台)

4.2 多态的实现

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


  • 由此可以看出,满足多态条件后,底层不再是编译时通过调用对象确定函数的地址,而是运行时到指向的对象的虚表中确定对应的虚函数的地址,这样就实现了指针或引用指向基类就调用基类的虚函数,指向派生类就调用派生类对应的虚函数
  • 第一张图,ptr指向的Person对象,调用的是Person的虚函数;第二张图,ptr指向的Student对
    象,调用的是Student的虚函数

在这里插入图片描述


  • 多态也可以发生在多个派生类

在这里插入图片描述


4.3 静态绑定和动态绑定

  • 对不满足多态条件的函数,调用时是在编译阶段绑定的,也就是编译时确定调用该类函数的地址,叫做静态绑定
  • 满足多态条件的函数,在运行时,到指向对象的虚函数表中找到调用该类函数的地址,也叫做动态绑定

在这里插入图片描述


4.4 虚函数表

  • 基类对象的虚函数表中存放基类所有虚函数的地址。同类型的对象共用同一张虚表,不同类型的对象各自有独立的虚表,所以基类和派生类有各自独立的虚表
  • 派生类由两部分构成,继承下来的基类和自己的成员,一般情况下,继承下来的基类中有虚函数表指针,自己就不会再生成虚函数表指针。但是要注意的这里继承下来的基类部分虚函数表指针和基类对象的虚函数表指针不是同一个,就像基类对象的成员和派生类对象中的基类对象成员也独立的
  • 派生类中重写的基类的虚函数,派生类的虚函数表中对应的虚函数就会被覆盖成派生类重写的虚函数地址
  • 派生类的虚函数表中包含,(1)基类的虚函数地址,(2)派生类重写的虚函数地址完成覆盖,派⽣类自己的虚函数地址三个部分
  • 虚函数表本质是⼀个存虚函数指针的指针数组,⼀般情况这个数组最后面放了⼀个0x00000000标记。(这个C++并没有进行规定,各个编译器自行定义的,vs系列编译器会再后面放个0x00000000标记,g++系列编译不会放)

在这里插入图片描述


在这里插入图片描述


  • 虚函数存在哪的?虚函数和普通函数⼀样的,编译好后是⼀段指令,都是存在代码段的,只是虚函数的地址又存到了虚表中
  • 虚函数表存在哪的?这个问题严格说并没有标准答案C++标准并没有规定,我们写下面的代码可以对比验证⼀下。vs下是存在代码段(常量区)

在这里插入图片描述


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

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

相关文章

Dive into LVGL (1) —— How LVGL works from top to down

0.briefly speaking 由于工作原因,最近开始接触到一些图形图像处理相关的知识,在这个过程中逐渐接触到了LVGL。作为一个开源的图形库,LVGL可以高效地为MCU、MPU等嵌入式设备构建美观的UI界面。我的手头也正好有一块集成了Vivante 2.5D GPU的…

【HarmonyOS 5】鸿蒙中进度条的使用详解

【HarmonyOS 5】鸿蒙中进度条的使用详解 一、HarmonyOS中Progress进度条的类型 HarmonyOS的ArkUI框架为开发者提供了多种类型的进度条,每种类型都有其独特的样式,以满足不同的设计需求。以下是几种常见的进度条类型: 线性进度条(…

OpenHarmony 开源鸿蒙南向开发——linux下使用make交叉编译第三方库——gmp

准备工作 请依照这篇文章搭建环境 OpenHarmony 开源鸿蒙南向开发——linux下使用make交叉编译第三方库——环境配置_openharmony交叉编译-CSDN博客 下载 wget https://gmplib.org/download/gmp/gmp-6.3.0.tar.xz 解压 tar -xf gmp-6.3.0.tar.xzcd gmp-6.3.0/ 环境变量 e…

量化交易策略的运行

✅ 什么是“策略的运行”? 在量化交易系统中,“策略的运行”并不一定意味着“每个策略对应一个线程”,但在大多数实际实现中,确实会使用线程、任务、协程或进程等形式来实现每个策略的独立调度与执行。 “运行”意味着策略开始生…

开平机:从原理到实践的全面技术剖析

一、开平机核心模块技术解析 1. 校平辊系的力学建模与辊型设计 校平机精度核心在于辊系设计,需通过弹塑性力学模型计算变形量。典型校平辊配置参数: 辊径比:校平辊直径(D)与板材厚度(t)需满足…

2、实验室测控系统 - /自动化与控制组件/lab-monitoring-system

76个工业组件库示例汇总 实验室测控系统开发组件 这是一个专为实验室设备数据采集与分析设计的可视化测控系统组件。采用工业风格界面设计,提供了丰富的动态数据展示与分析功能,可应用于各类实验室环境中的设备监控和数据处理。 功能特点 多设备管理…

在 Kotlin 中什么是委托属性,简要说说其使用场景和原理

在 Kotlin 中,属性委托和类委托是两种通过 by 关键字实现的强大特性,它们通过“委托”机制将行为或实现逻辑委托给其他对象,从而实现代码的复用和解耦。 1 属性委托 定义: 允许把属性的 get 和 set 方法的具体实现委托给另一个对…

AI星智协脑:智能驱动的高效协作管理平台全解读

前言 想象一下:早上刚开电脑,十几条未读消息如机关枪般扫射而来,各路任务像陨石雨一样砸向你,会议排得比热播剧还密集,文档版本堪比宫斗剧剧情反转,同事围着你转圈追KPI,活脱脱一场《职场大逃杀…

Web 架构之数据读写分离

文章目录 一、引言二、数据读写分离原理2.1 基本概念2.2 工作流程 三、数据读写分离的实现方式3.1 基于中间件实现3.2 应用程序层面实现 四、常见问题及解决方法4.1 数据一致性问题4.2 从数据库负载均衡问题4.3 主从复制故障问题 五、思维导图六、总结 一、引言 在 Web应用的开…

【软件设计师:数据结构】1.数据结构基础(一)

一 线性表 1.线性表定义 线性表是n个元素的有限序列,通常记为(a1,a2,…,an)。 特点: 存在惟一的表头和表尾。除了表头外,表中的每一个元素均只有惟一的直接前驱。除了表尾外,表中的每一个元素均只有惟一的直接后继。2.线性表的存储结构 (1)顺序存储 是用一组地址连续…

实践005-Gitlab CICD全项目整合

文章目录 环境准备环境准备集成Kubernetes Gitlab CICD项目整合项目整合整合设计 后端Java项目部署后端Java项目静态检查后端Java项目镜像构建创建Java项目部署文件创建完整流水线 前端webui项目部署前端webui项目镜像构建创建webui项目部署文件创建完整流水线 构建父子类型流水…

鸿蒙开发:dialog库做了一些优化

前言 本文基于Api13 dialog库是我去年5月份开发了一个便捷弹窗库,主打一个使用简单,一经推出,在dialog领域下载量稳居在前,可以说是非常受欢迎的;但是,之前的版本仍然有着可优化的空间,比如弹窗…

Windows 10 无法启动或黑屏的修复指南(适用于更新失败或磁盘故障)

Windows 10 无法启动或黑屏的修复指南(适用于更新失败或磁盘故障) 当 Windows 10 突然无法启动(黑屏、无限重启、更新失败后断电等情况),很可能是由于启动引导程序损坏或系统映像异常(如系统磁盘出现坏道&…

MCP开发入门

MCP开发入门 官方文档: https://modelcontextprotocol.io/introduction 入门教程: https://github.com/liaokongVFX/MCP-Chinese-Getting-Started-Guide 本文源代码:https://github.com/youngqqcn/mcp-server-demo 什么是MCP? 模型上下文协议&#xff…

PX4开始之旅(二)通过自定义 MAVLink 消息与 QGroundControl (QGC) 通信

核心知识点:通过自定义 MAVLink 消息与 QGroundControl (QGC) 通信 1. 通俗易懂的解释 想象一下,MAVLink 就像是无人机(飞控)和地面站(QGroundControl)之间约定好的一种“语言”。这种语言有很多标准的“…

AI视频智能分析网关打造社区/工厂/校园/仓库智慧消防实现精准化安全管控

一、背景 随着社区、商业场所对消防安全要求日益提升,传统消防系统已难以满足智能化、精细化管理需求。智能分析网关融合物联网与人工智能技术,具备强大的数据处理与分析能力,可全面升级消防系统。将其融入消防系统各层级,搭建智…

深度学习基础--目标检测常见算法简介(R-CNN、Fast R-CNN、Faster R-CNN、Mask R-CNN、SSD、YOLO)

博主简介:努力学习的22级本科生一枚 🌟​;探索AI算法,C,go语言的世界;在迷茫中寻找光芒​🌸​ 博客主页:羊小猪~~-CSDN博客 内容简介:常见目标检测算法简介​&#x1f…

传输层协议UDP和TCP

传输层协议UDP和TCP 1、UDP2、TCP2.1、TCP协议段格式2.2、确认应答(ACK)机制2.3、超时重传机制2.4、连接管理机制2.5、理解CLOSE_WAIT状态2.6、理解TIME_WAIT状态2.7、流量控制2.8、滑动窗口2.9、拥塞控制2.10、延迟应答2.11、捎带应答2.12、面向字节流2.13、粘包问题2.14、TCP…

PMIC电源管理模块的PCB设计

目录 PMU模块简介 PMU的PCB设计 PMU模块简介 PMIC(电源管理集成电路)是现代电子设备的核心模块,负责高效协调多路电源的转换、分配与监控。它通过集成DC-DC降压/升压、LDO线性稳压、电池充电管理、功耗状态切换等功能,替代传统分…

Ubuntu 配置网络接口端点(静态 IP 地址)详细教程

在 Ubuntu 系统中,配置网络接口端点通常指的是为您的有线或无线网卡设置一个固定的 IP 地址、子网掩码、网关以及 DNS 服务器。这对于服务器或者需要稳定网络标识的设备来说非常重要。 使用 Netplan (Ubuntu 17.10 及更高版本的默认方式)使用 ifupdown (通过 /etc/…