当前位置: 首页 > news >正文

多态(上)【C++】

文章目录

  • 多态的概念
  • 多态的实现
    • 多态产生的条件
      • 什么是虚函数?
      • 虚函数的重写和协变
        • 重写
        • 协变
    • 析构函数的重写
      • 为什么有必要要让析构函数构成重写?

多态的概念

C++中的多态是面向对象编程(OOP)的一个核心特性,指的是同一个接口可以用于不同类型的对象,而这些对象对同一消息可以做出不同的响应。
具体来说,多态性允许以统一的方式处理不同类型的对象,使得代码更加灵活和可扩展。

多态通俗地说就是“多种形态”。
在不同的对象上执行相同的行为时,由于对象类型的不同,会产生不同的结果
举例来说,对于“买票”这个行为,普通人买票是全价,学生买票是半价,军人买票享有优先权。不同类型的对象(普通人、学生、军人)对同一行为产生了不同的响应。

多态的表现形式一般就是:
指向的对象不同,调用同名的函数,具体调用到的函数就不同

父类A和子类B中都有一个函数func(),构成多态的时候:

A*p=new A;  指向父类对象
p->func();  就调用父类中的funcA*p=new B;  指向子类对象
p->func();  就调用子类中的func

多态的实现

多态产生的条件

  1. 子类必须重写(或者协变)父类的虚函数
  2. 必须是父类的指针或者引用调用构成重写的虚函数


在这里插入图片描述


什么是虚函数?

在C++中,虚函数是使用virtual关键字修饰的非静态成员函数。
虚函数的主要作用是允许在派生类中重新定义基类的函数,从而实现多态。

关于虚函数的一些注意点:

  1. 虚函数就是为了实现多态而存在的,而且支持虚函数是需要付出一定代价
    所以如果不实现多态,就不要定义虚函数

  2. 静态成员函数不能做虚函数
    因为
    ①虚表指针存在对象里,但是静态成员的生命周期比对象长,而且静态成员函数里面没有this指针,就找不到对象
    ②因为静态的特性:在以该父类为起始的整个继承体系中只有一份,如果实行多态的话就有多份了,这不符合静态的特性

  3. 在父类中声明为虚函数的成员函数,继承到子类后,这个成员函数即使没有virtual修饰也是虚函数。
    但是还是建议在子类中也加上virtual修饰,这样代码的可读性更高


虚函数的重写和协变

重写

子类中有与父类完全相同【返回值类型、函数名、参数列表完全相同】的虚函数,称子类的虚函数重写了父类的虚函数。

在这里插入图片描述


协变

子类和父类的虚函数的返回值可以不同【其他两个(函数名,参数表)依旧必须相同】,但是满足以下3个条件的就构成协变

  1. 父类的虚函数的返回值是一个父类类型的指针或者引用
  2. 子类的虚函数的返回值是一个子类类型的指针或者引用
  3. 子类和父类的返回值中的子类和父类必须是同一个继承体系的

    在这里插入图片描述

析构函数的重写

重写的要求上面说了,即必须子类和父类的虚函数的返回值函数名参数表都相同才可以构成重写
但是析构函数名字的特殊性【~类名】,就让同一作用域中的两个类的析构函数的名字不可能相同,因为这两个类的类名不可能相同

所以析构函数不能构成重写吗?
并非如此。
反而因为析构函数的多态非常重要,C++又专门为它开了一条路:
任意一个类,只要它加入了继承体系,那么它的析构函数的名字就会被改成destructor

因为析构函数没有返回值和参数表,所以析构函数构成重写非常简单,只需要在父类的析构函数前面加一个virtual,让它变成虚函数就可以了。


为什么有必要要让析构函数构成重写?

如果析构函数没有构成重写,那么下面这种情况就会内存泄露
因为析构函数没有构成多态,所以delete时候只会看指针的类型是什么,据此调用析构函数
所以只调用了父类的析构
在这里插入图片描述
上面的这种情况【父类指针指向new出来的子类对象】在使用多态的时候还是挺常见的,所以解决很有必要


当析构函数构成多态的时候:
因为析构函数构成了多态,所以delete时候就会看指针的指向的对象是什么,据此调用析构函数
所以会调用子类的析构
在这里插入图片描述


相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 如何搞定日语翻译?试试这四款工具
  • FreeRTOS学习(2)延时函数的封装
  • 【白话树】之 树的基本知识、存储结构和二叉树转换
  • MySQL 子查询
  • hiresfix_latent 使用Upscale放大节点 对图片进行放大Comfyui
  • 众店绿色积分模式:引领消费新风尚,共筑商业新生态
  • 研1日记10
  • 深入探索系统架构设计
  • CCF编程能力等级认证GESP—C++7级—20240907
  • 利用Idea远程调试
  • Python 从入门到实战15(字符串其它操作)
  • Day14笔记-函数简介定义调用参数一
  • 【Java】基于JWT+Token实现完整登入功能(原理+实操图解)
  • 鸿蒙开发5.0【帧率】解析
  • 宠物毛发对人体有什么危害?宠物空气净化器小米、希喂、352对比实测
  • 【Leetcode】101. 对称二叉树
  • 自己简单写的 事件订阅机制
  • 【5+】跨webview多页面 触发事件(二)
  • Android 架构优化~MVP 架构改造
  • create-react-app项目添加less配置
  • Druid 在有赞的实践
  • GDB 调试 Mysql 实战(三)优先队列排序算法中的行记录长度统计是怎么来的(上)...
  • Java 实战开发之spring、logback配置及chrome开发神器(六)
  • JavaScript 无符号位移运算符 三个大于号 的使用方法
  • JavaScript新鲜事·第5期
  • 工程优化暨babel升级小记
  • 基于游标的分页接口实现
  • 类orAPI - 收藏集 - 掘金
  • 理解在java “”i=i++;”所发生的事情
  • 区块链将重新定义世界
  • 删除表内多余的重复数据
  • 微信小程序设置上一页数据
  • 写给高年级小学生看的《Bash 指南》
  • Oracle Portal 11g Diagnostics using Remote Diagnostic Agent (RDA) [ID 1059805.
  • 3月27日云栖精选夜读 | 从 “城市大脑”实践,瞭望未来城市源起 ...
  • 400多位云计算专家和开发者,加入了同一个组织 ...
  • #define、const、typedef的差别
  • #NOIP 2014#day.2 T1 无限网络发射器选址
  • #QT 笔记一
  • $.ajax中的eval及dataType
  • (4)Elastix图像配准:3D图像
  • (delphi11最新学习资料) Object Pascal 学习笔记---第2章第五节(日期和时间)
  • (LLM) 很笨
  • (poj1.2.1)1970(筛选法模拟)
  • (Repost) Getting Genode with TrustZone on the i.MX
  • (二)c52学习之旅-简单了解单片机
  • (附源码)springboot金融新闻信息服务系统 毕业设计651450
  • (生成器)yield与(迭代器)generator
  • (十八)SpringBoot之发送QQ邮件
  • (十二)springboot实战——SSE服务推送事件案例实现
  • (原创)Stanford Machine Learning (by Andrew NG) --- (week 9) Anomaly DetectionRecommender Systems...
  • (原創) 是否该学PetShop将Model和BLL分开? (.NET) (N-Tier) (PetShop) (OO)
  • (转)清华学霸演讲稿:永远不要说你已经尽力了
  • .jks文件(JAVA KeyStore)
  • .net core使用ef 6