【C++】-多态的语法细节详解

在这里插入图片描述
💖作者:小树苗渴望变成参天大树🎈
🎉作者宣言:认真写好每一篇博客💤
🎊作者gitee:gitee✨
💞作者专栏:C语言,数据结构初阶,Linux,C++ 动态规划算法🎄
如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧!

文章目录

  • 前言
  • 一、多态的概念?
    • 1.1 概念
  • 二. 多态的定义及实现
    • 2.1多态的构成条件
    • 2.2 C++11 override 和 final
    • 2.3 重载、覆盖(重写)、隐藏(重定义)的对比
  • 三、抽象类
    • 3.1 概念
    • 3 .2 接口继承和实现继承
  • 四、总结


前言

这篇我们开始讲解关于多态的语法细节,C++难学的第一个点在类和对象刚开始,第二个点就是在继承和多态,我们已经度过第一个点了,接下来要迈进我们第二个难关,大家要耐下心来进行学习,博主也会梳理好逻辑,方便大家学习,话不多说我们开始学习多态。


本章重点

  1. 多态的概念
  2. 多态的定义及实现
  3. 抽象类

一、多态的概念?

我们C++是一个面向对象的语言,我们通过类描述一个个的对象,但是每个对象可能有多种状态,多态是建立在继承的,我们来看看多态的例子:

1.1 概念

多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。
在这里插入图片描述
第一个例子: 比如买票这个行为,当普通人买票时,是全价买票;学生买票时,是半价买票;军人买票时是优先买票

第二个例子: 再举个栗子: 最近为了争夺在线支付市场,支付宝年底经常会做诱人的扫红包-支付-给奖励金的活动。那么大家想想为什么有人扫的红包又大又新鲜8块、10块…,而有人扫的红包都是1毛,5毛…。其实这背后也是一个多态行为。支付宝首先会分析你的账户数据,比如你是新用户、比如你没有经常支付宝支付等等,那么你需要被鼓励使用支付宝,那么就你扫码金额 = random()%99;比如你经常使用支付宝支付或者支付宝账户中常年没钱,那么就不需要太鼓励你
去使用支付宝,那么就你扫码金额 = random()%1;总结一下:同样是扫码动作,不同的用户扫得到的不一样的红包,这也是一种多态行为。ps:支付宝红包问题纯属瞎编,大家仅供娱乐。

通过这两个例子,我们应该知道为什么要有多态,是因为我们实现世界中有这种多种状态的情况

二. 多态的定义及实现

2.1多态的构成条件

多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。比如Student继承了Person。Person对象买票全价,Student对象买票半价。


class Person {
public:virtual void BuyTicket() { cout << "买票-全价" << endl; }
};
class Student : public Person {
public:virtual void BuyTicket() { cout << "买票-半价" << endl; }
};
void Func(Person& p)
{p.BuyTicket();
}
int main()
{Person p;Student s;Func(p);Func(s);return 0;
}

在这里插入图片描述
这里引入一个概念:虚函数

虚函数:即被virtual修饰的类成员函数称为虚函数。

并且静态的函数不能当成虚函数,虚函数不能定义和声明分离,只要普通函数可以当成虚函数去使用

通过这个例子相信大家应该知道多态的基本用法了,我们来看看构成多态的基本条件:

  1. 必须通过基类的指针或者引用调用虚函数(通过对象去调用时不行的)讲底层的时候在进行介绍
    在这里插入图片描述

  2. 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写
    在这里插入图片描述

基类的的函数必须加virtual,变成虚函数,子类必须重写基类的虚函数

虚函数重写的细节:

  1. 派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的
    返回值类型、函数名字、参数列表完全相同(即类型相同就行)),称子类的虚函数重写了基类的虚函数。
    在这里插入图片描述
  2. 子类的重写虚函数前面可以不用加virtual,但是建议加上(后面会介绍这个可能为析构函数为产生的)
    在这里插入图片描述

虚函数重写的两种例外:

  1. 协变(基类与派生类虚函数返回值类型不同)
    派生类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回必须任意基类对象的指针或者引用,派生类虚函数返回必须任意派生类对象的指针或者引用时,称为协变。(了解),引用我就不演示了效果是一样的。
    在这里插入图片描述
  2. 析构函数的重写(基类与派生类析构函数的名字不同)

在讲解这个例外之前在补充一个知识点,实现多态后:多态的调用看的是指向的对象,而不是看类型,而普通对象的调用时是看当前调用者的类型,可以简单理解,上面的多态通过指针或者引用去调用就是多态的调用,使用对象去调用就是对象的调用,想要达到通过指向的对象去调用就必须先形成多态才可以。(在讲解底层的时候会讲到,也就是分析为什么多态需要的指针或者引用去调用而通过对象去调用不行)

有了上面的补充我们来看例子:

class A
{
public:virtual ~A(){cout << "~A()" << endl;}
};
class B:public A
{
public:virtual ~B(){	cout << "~B()" << endl;}
};
int main()
{A a;B b;return 0;
}

在这里插入图片描述

在继承的使用那一篇说到过,我们析构函数都是先析构子在析构父,那我们上面这个看着有点奇怪,两个函数名不是一样的,而且没有返回值,这应该没有构成重写吧??所以这是一个例外,析构函数的重写可以没有返回值,而且在编译的时候父子类的析构函数名都被统一处理为了destructor,所以函数名也是一样的,够成虚函数的重写

如果不是虚函数的重写会发生情况??
在这里插入图片描述
我们看到运行结果一样的,有的人就会说那是不是虚函数都是一样的,那为什么要使他变成虚函数呢??
原因是要适应下面的场景:
在这里插入图片描述

我们发现它没有去调用B类的析构函数,p没有进行释放,造成内存泄漏了,为什么会这样??
我们的delete b实际上是两份构成b->destructor()+operator delete
我们new B一个对象,赋值给A*,它去调用函数是普通对象的调用,因为没有实现多态,看调用者的类型为A*,所以去调用了A类的析构函数,就永远调不到B类的析构,我们只要使父类的析构函数是虚函数,因为编译器本身会把所有类的析构函数统一处理成相同名字的函数,只要父类函数是虚函数,子类加不加virtual都构成虚函数的重写,此时就构成多态了,那么此时又是指针或者引用去调用,那么指向哪个对象就去调用哪个的函数
在这里插入图片描述
所以通过这个例子也说明了,多态调用和普通调用是不一样的,等底层原理的时候会给大家一一解释的。也解决了析构函数可以是虚函数,为什么要变成虚函数,原因就是为了解决上面的出现的情况,也解决了我上面说过为什么父类的virtual必须加,而子类的不需要,因为设计的时候,析构函数就不用加,也是防止写的人忘记加而导致的问题,后面为了保持一致,所以虚函数在重写的时候可加可不加。

所以我们在实现类继承或者多态的时候尽量都把基类的virtual给加上,防止出错

2.2 C++11 override 和 final

从上面可以看出,C++对函数重写的要求比较严格,但是有些情况下由于疏忽,可能会导致函数名字母次序写反而无法构成重载,而这种错误在编译期间是不会报出的,只有在程序运行时没有得到预期结果才来debug会得不偿失,因此:C++11提供了override和final两个关键字,可以帮助用户检测是否重写。

  1. final:修饰虚函数,表示该虚函数不能再被重写
    在这里插入图片描述

博主认为一个虚函数不能被重写,那么它是虚函数的意义就没有了,虚函数就是为了多态的,多态就是需要虚函数的重写的,所以final用到的也特别少,反而下面这个关键字用到还是比较多的。

final还有一个用途:
设计一个类,不能被继承按照以往的案例,
(1)我们可以将构造函数私有化

class A
{
private:A(){}
};

我们没有办法创建类对象了,我们可以向外提供一个接口:

class A
{
public: A createinit(){return A();}
private:A(){}
};

就面临一个问题,我们的createinit需要通过对象去调,而这个函数就是为了创建对象的,所以我们可以设置成静态的,通过类名去调用:

class A
{
public: static A createinit(){return A();}
private:A(){}
};
int main()
{A::createinit();return 0;
}

(2)将析构函数私有化,就调用不到析构函数了
(3)使用final进行修饰类
在这里插入图片描述

final必须放在后面。

  1. override: 检查派生类虚函数是否重写了基类某个虚函数,如果没有重写编译报错。
    在这里插入图片描述

就是怕你想要fun是多态,但是基类忘记写了,代码少你可以一下子看出来,代码多了就不好看了。

2.3 重载、覆盖(重写)、隐藏(重定义)的对比

覆盖是底层的说法,重写是语法的说法
在这里插入图片描述

三、抽象类

3.1 概念

在虚函数的后面写上 =0 ,则这个函数为纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口类),抽象类不能实例化出对象。派生类继承后也不能实例化出对象,只有重写纯虚函数,派生类才能实例化出对象。纯虚函数规范了派生类必须重写,另外纯虚函数更体现出了接口继承。

class Car
{
public:virtual void Drive() = 0;
};
class Benz :public Car
{
public:virtual void Drive(){cout << "Benz-舒适" << endl;}
};
class BMW :public Car
{
public:virtual void Drive(){cout << "BMW-操控" << endl;}
};
void Test()
{Car* pBenz = new Benz;pBenz->Drive();Car* pBMW = new BMW;pBMW->Drive();
}

在这里插入图片描述

3 .2 接口继承和实现继承

普通函数的继承是一种实现继承,派生类继承了基类函数,可以使用函数,继承的是函数的实现。虚函数的继承是一种接口继承,派生类继承的是基类虚函数的接口,目的是为了重写,达成多态,继承的是接口。所以如果不实现多态,不要把函数定义成虚函数

抽象类是多态的一种约束,你是抽象类,就必须使用多态,不然都实例化不出对象,就一点用都没有

四、总结

说到这里我们多态的具体使用细节就到这里了,说实话多态形成的条件还是特别多的,那条件多,就更来说明底层设计的更复杂,需要很多条件才能适应它涉及的场景,博主猜想:先设计出来多态,然后使用的时候发现需要这些条件才能满足,才导致多态的语法细节比较多,但是没事,博主会给大家讲解明白的,等我们学习了底层原理之后,就会恍然大悟,前面一会语法为什么要这样就解决了,我们今天就到此为止,我们下篇再见吧。。
请添加图片描述

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

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

相关文章

GPT-3.5:ChatGPT的奇妙之处和革命性进步

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

苹果开发“Apple GPT”AI科技迎来新格局

根据彭博社的马克・古尔曼&#xff08;Mark Gurman&#xff09;报道&#xff0c;苹果内部正在开发“Apple GPT”人工智能项目&#xff0c;足以媲美 OpenAI 的 ChatGPT &#xff0c;预计明年推出。就在彭博社消息发出之后&#xff0c;苹果股价上涨了2.3%&#xff0c;市值顶峰时增…

题目4 命令执行(保姆级教程)

url&#xff1a;http://192.168.154.253:84/ #打开http://XXX:81/&#xff0c;XXX为靶机的ip地址 审题 1、打开题目看到有一个提示&#xff0c;此题目需要通过利用命令执行漏洞执行Linux命令获取webshell&#xff0c;最后从根目录下key.php文件中获得flag 2、开始答题 第一步&…

css设置八等分圆

现需要上图样式的布局&#xff0c;我通过两张向右方的图片&#xff0c;通过定位和旋转完成了布局。 问题&#xff1a; 由于是通过旋转获取到的样式&#xff0c;实际的盒子是一个长方形&#xff0c;当鼠标移入对应的箭头时选中的可能是其他盒子&#xff0c;如第一张设计稿可以看…

Ngrok 的绝佳替代品,内网穿透神器 Serveo

什么是 Serveo Serveo 是一个免费的内网穿透服务&#xff0c;Serveo 可以将本地计算机暴露在互联网上&#xff0c;官方声称其为 Ngrok 的绝佳替代品。 Serveo 其最大优点是使用现有的 SSH 客户端&#xff0c;无需安装任何客户端软件即可完成端口转发。 Serveo 工作原理很简单…

解密数字孪生:解决实际问题的神奇技术

数字孪生是一种将现实世界与数字世界相连接的创新技术&#xff0c;通过将实际物体或系统的数据和行为模拟到数字平台上&#xff0c;实现真实与虚拟之间的交互和信息共享。数字孪生的应用不仅仅局限于虚拟现实&#xff08;VR&#xff09;和仿真领域&#xff0c;它在解决实际问题…

泰晓科技发布 Linux Lab v1.2 正式版

导读近日消息&#xff0c;Linux Lab 是一套用于 Linux 内核学习、开发和测试的即时实验室&#xff0c;官方称其“可以极速搭建和使用&#xff0c;功能强大&#xff0c;用法简单”。 自去年 12 月份发布 Linux Lab v1.1 后&#xff0c;v1.2 正式版目前已经发布于 GitHub 及 Gite…

为什么 Linux 内核协议栈会丢弃 SYN 数据包

最近了解到 SYN 数据包丢弃的问题&#xff0c;网上有一些资料&#xff0c;这里记录分享一下。 serverfault上的重要信息 tcp - No SYN-ACK Packet from server - Server Fault 信息如下&#xff1a; My embedded system with LwIP is the client and I have server1 and ser…

文艺类《匠心》简介及投稿要求

文艺类《匠心》简介及投稿要求 《匠心》期刊简介&#xff1a; 主管单位&#xff1a;内蒙古画报社 主办单位&#xff1a;内蒙古画报社 国际刊号&#xff1a;ISSN:1672-9099 国内刊号&#xff1a;CN:15-1383/J 发行周期&#xff1a;月刊;收录网站&#xff1a;中国知网收录 …

LiveGBS流媒体平台GB/T28181常见问题-TOKEN有效期是多久如何设置token有效期StreamToken和URLToken

LiveGBS中TOKEN有效期是多久如何设置token有效期StreamToken和URLToken 1、获取TOKEN2、TOKEN有效期3、默认token有效期3、自定义token加密key3.1、token_key3.2、stream_token_key 4、如何配置一直有效的token4.1、URLToken4.2、StreamToken 5、动态有效期6、流地址鉴权开启后…

git的使用

git使用 Git操作基本指令&#xff1a;分支操作&#xff1a;操作远程仓库&#xff1a;文件操作比较文件差异删除文件撤销文件重命名文件 操作标签SSH密钥git错误示例1、git status&#xff08;或任何其他git命令&#xff09;然后会出现fatal: Not a git repository (or any of t…

智能管理轻松搞定!文件批量改名并按数量平均分类,自动新建文件夹保存!

我们面对大量文件需要整理和管理时&#xff0c;批量改名和分类是一项繁琐而重要的任务。为了帮助您高效完成这项工作&#xff0c;我们介绍了一种智能方法&#xff1a;按数量平均分类并自动保存文件&#xff0c;让您轻松整理文件夹内容。 首先第一步&#xff0c;我们要进入文件…

swift简单弹幕例子,仿哔哩哔哩

先看例子 每个弹幕的速度都是不一样的&#xff0c;支持弹幕整体开始暂停。 如果弹幕实在是太多了&#xff0c;有个缓冲队列&#xff0c;不停的重试能否显示&#xff0c;保证文字都能显示全&#xff0c;并且每条都能显示。 实现是基于 CADisplayLink 实现的&#xff0c;如此来…

工业以太网的发展历程与应用前景

工业以太网是在工业自动化和物联网领域广泛使用的通信网络&#xff0c;它具有应用广泛、价格低廉、通信速率高、软硬件产品丰富、应用支持技术成熟等优点&#xff0c;目前它已经在工业企业综合自动化系统中的资源管理层、执行制造层得到了广泛应用&#xff0c;并呈现向下延伸直…

Verilog 学习之路(三)——牛客刷题篇

1.输入序列连续的序列检测 题面 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kJH9kHFH-1690301233803)(https://s2.loli.net/2023/07/26/HJPXR2mhbaVCG6d.png)]思路 对于序列检测题目&#xff0c;常规的解法有两种&#xff1a;状态机法和序列缓存…

概率论和随机过程的学习和整理--番外16,N合1的合成问题的求平均个数,次数,阶数

目录 1 问题 2 用条件期望&#xff0c;求合成的次数 2.1 思路1 2.2 思路2 3 用条件期望&#xff0c;求合成的个数 3.1 令X表示用材料1往上合成时&#xff0c;合成材料2的个数 3.2 令Y表示用材料1往上合成时&#xff0c;合成材料3的个数 4 用条件期望&#xff0c;求合成…

现行业供应链数字化转型难的最根本原因是什么?

由于各种原因&#xff0c;行业供应链的数字化转型可能充满挑战。然而&#xff0c;最根本的原因之一是供应链本身固有的复杂性和碎片化。以下是造成这一困难的一些关键因素&#xff1a; 1.缺乏标准化&#xff1a;供应链通常涉及多个组织、系统和流程&#xff0c;这些组织、系统…

删除主表 子表外键没有索引的性能优化

整个表147M&#xff0c;执行时一个CPU耗尽&#xff0c; buffer gets 超过1个G&#xff0c; 启用并行也没有用 今天开发的同事问有个表上的数据为什么删不掉&#xff1f;我看了一下&#xff0c;也就不到100000条数据&#xff0c;表上有外键&#xff0c;等了5分钟hang在那里&…

网络安全系统教程+学习路线(自学笔记)

一、什么是网络安全 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 无论网络、Web、移动、桌面、云等哪个领域&#xff0c;都有攻与防两面…

Upload-Labs通关

问题 记录BUG—在uploadlabs第三关中—关于phpstudy中修改httpd.conf依旧无法解析.php3d等问题_upload第三关常见错误_dfzy$_$的博客-CSDN博客 我们首先先来了解一下什么是文件上传 首先 很简单 文件上传就是 需要用户进行上传文件 图片或视频等信息但是如果用户恶意上传木马…