一篇文章看懂C++三大特性——多态的定义和使用

news2025/2/26 19:23:55

目录

前文

一,什么是多态?

1.1 多态的概念

二, 多态的定义及实现

2.1 多态的构成条件

2.2 虚函数

2.3 虚函数的重写

2.3.1 虚函数重写的两个例外

2.4 C++ override 和 final

2.5 重载,重写(覆盖),隐藏(重定义)的区别

 三,抽象类

3.1 概念

3.2 接口継承和实现継承

总结


前文

C++三大特性——封装,継承,多态,前两个我们都已经学习过了,现在让我们一起来学习最后一个特性——多态

一,什么是多态?

1.1 多态的概念

 多态其实就是多种形态,实际上就是当完成某个行动时,不同的对象完成会产生不同的状况。如上图某景点门票,大学生,普通人,儿童所需要的票价都是不一样的,这就算是多态在实际生活的一种应用。

二, 多态的定义及实现

2.1 多态的构成条件

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

但是我们需要主要构成多态要满足下面两个条件(后面会讲到两个特例)

1. 被调用的函数必须是虚函数,而且子类要对父类的虚函数进行重写

2. 必须通过父类的指针或者引用调用虚函数

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
class Person
{
public:
	virtual void Buyticket()
	{
		cout << "全价票" << endl;
	}
};

class Student :public Person
{
public:
	virtual void Buyticket()
	{
		cout << "半价票" << endl;
	}
};

void Func1(Person& p)
{
	p.Buyticket();
}

int main()
{
	Person p;
	Student s;

	Func1(p);
	Func1(s);
	return 0;
}

以上面为例,我们先简单使用一下多态,上述代码具体实现如下。

 看到这里可能有的老铁很好奇,这怎么这么神奇,加一个virtual就可以实现,底层是怎么实现的?我们不要急,饭要一口一口吃,我们先来了解一下多态两个必要条件都离不开的虚函数

2.2 虚函数

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

class Person
{
public:
	virtual void Buyticket()
	{
		cout << "全价票" << endl;
	}
};

2.3 虚函数的重写

虚函数的重写是多态必不可少的条件之一,接下来我们先了解一下到底什么是虚函数的重写。

虚函数的重写(覆盖):子类中有一个和父类完全相同的虚函数(三同,即子类虚函数与父类虚函数的函数名,参数,返回值完全相同。),这样的称作子类的虚函数重写了父类的虚函数。

举个例子:

class Person
{
public:
	virtual void Buyticket()
	{
		cout << "全价票" << endl;
	}
};

class Student :public Person
{
public:
	virtual void Buyticket()
	{
		cout << "半价票" << endl;
	}
};

注意:这里还有另一种写法,就是在重写父类虚函数时,子类的虚函数前面可以不加virtual关键字,仍然构成重写,这是因为子类继承了父类的虚函数接口,即使不加virtual也保持虚函数属性,但是这种写法可读性差,还是建议用上面的写法

class Person
{
public:
	virtual void Buyticket()
	{
		cout << "全价票" << endl;
	}
};

class Student :public Person
{
public:
	//virtual void Buyticket()
	void Buyticket()
	{
		cout << "半价票" << endl;
	}
};

2.3.1 虚函数重写的两个例外

1. 协变(父类与子类虚函数的返回值不同)

派生类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变。这个实际用到的不多,我们了解一下即可

class Person
{
public:
	virtual Person* Buyticket()
	{
		cout << "全价票" << endl;
		return this;
	}
};

class Student :public Person
{
public:
	virtual Student* Buyticket()
	{
		cout << "半价票" << endl;
		return this;
	}
};

2. 析构函数的重写(父类与子类析构函数名不同)

如果父类的析构函数是虚函数,那么子类的析构函数只要定义,无论加不加virtual关键字,都与父类的析构函数形成重写,这里父类和子类的析构函数名字不同,老铁们可能会觉得不满足上面多态的两个必要条件,实际上不是,在编译后,编译器会将类的析构函数统一命名为~destructor()

析构函数的应用场景也是有的,如下面的情况。

 在上面例子中,只有Student的析构函数重写了Person的析构函数,delete对象调用析构函数,才能构成多态,才能保证p1,p2正确释放。

2.4 C++ override 和 final

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

1.final:修饰虚函数,表示该虚函数不能再被重写

class Person
{
public:
	virtual void Buyticket final()
	{
		cout << "全价票" << endl;
	}
};

class Student :public Person
{
public:
	virtual void Buyticket()
	{
		cout << "半价票" << endl;
	}
};

2. override: 检查派生类虚函数是否重写了基类某个虚函数,如果没有重写编译报错。

class Person
{
public:
	virtual void Buyticket()
	{
		cout << "全价票" << endl;
	}
};

class Student :public Person
{
public:
	virtual void Buyticket override()
	{
		cout << "半价票" << endl;
	}
};

2.5 重载,重写(覆盖),隐藏(重定义)的区别

 三,抽象类

3.1 概念

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

 上文我们提到了接口継承,那么什么是接口継承和实现継承

3.2 接口継承和实现継承

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

总结

多态的基本内容到这里就告一段落了,下一篇文章讲解多态的底层原理,希望铁子们能有所收获

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

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

相关文章

代码随想录刷题-双指针总结篇

文章目录双指针移除元素习题我的解法双指针优化反转字符串习题我的解法剑指 Offer 05. 替换空格习题我的解法正确解法反转字符串里的单词习题我的解法反转链表习题我的解法删除链表的倒数第 N 个节点习题我的解法相交链表习题我的解法环形链表 II习题我的解法三数之和习题我的解…

Unity VFX -- (3)创建环境粒子系统

粒子系统中最常用也最重要的一种使用场景是实现天气效果。只需要做很少修改&#xff0c;场景就能很快从蓝天白云变成雪花飘舞。 和之前看到的粒子系统从一个源头发出粒子的情况不同&#xff0c;天气效果完全围绕着场景。 新增和放置一个新的粒子系统 为了创建下雨或下雪的天气…

【从零开始学Skynet】基础篇(三):服务模块常用API

1、服务模块 Skynet提供了开启服务和发送消息的API&#xff0c;必须要先掌握它们。列出了Skynet中8个最重要的API&#xff0c;PingPong程序会用到它们。 Lua API说明newservice(name, ...) 启动一个名为 name 的新服务&#xff0c;并返回服务的地址。 start(func) …

【学习笔记】unity脚本学习(二)(Time时间体系、Random随机数、Mathf数学运算)

目录Time时间体系timeScalemaximumDeltaTimefixedDeltaTimecaptureDeltaTimedeltaTime整体展示Random随机数Mathf数学运算IMathf.Round()Mathf.Ceil() Mathf.CeilToInt()Mathf.SignMathf.ClampMathf数学运算II-曲线变换Lerp 线性插值LerpAngleSmoothDamp疑问&#xff1a;Smooth…

自己动手写编译器:DFA跳转表的压缩算法

在编译器开发体系中有两套框架&#xff0c;一个叫"lex && yacc", 另一个名气更大叫llvm&#xff0c;这两都是开发编译器的框架&#xff0c;我们只要设置好配置文件&#xff0c;那么他们就会生成相应的编译器代码&#xff0c;通常是c或者c代码&#xff0c;然后…

AI自动寻路AStar算法【图示讲解原理】

文章目录AI自动寻路AStar算法背景AStar算法原理AStar寻路步骤AStar具体寻路过程AStar代码实现运行结果AI自动寻路AStar算法 背景 AI自动寻路的算法可以分为以下几种&#xff1a; 1、A*算法&#xff1a;A*算法是一种启发式搜索算法&#xff0c;它利用启发函数&#xff08;heu…

Jmeter接口测试和性能测试

目前最新版本发展到5.0版本&#xff0c;需要Java7以上版本环境&#xff0c;下载解压目录后&#xff0c;进入\apache-jmeter-5.0\bin\&#xff0c;双击ApacheJMeter.jar文件启动JMemter。 1、创建测试任务 添加线程组&#xff0c;右击测试计划&#xff0c;在快捷菜单单击添加-…

STM32F103RCT6驱动SG90舵机-完成正反转角度控制

一、SG90舵机介绍 SG90是一种微型舵机&#xff0c;也被称为伺服电机。它是一种小型、低成本的直流电机&#xff0c;通常用于模型和机器人控制等应用中。SG90舵机可以通过电子信号来控制其精确的位置和速度。它具有体积小、重量轻、响应快等特点&#xff0c;因此在各种小型机械…

亚马逊测评只能下单上好评?卖家倾向养号测评还有这些骚操作

亚马逊测评这对于绝大部分亚马逊卖家来说都不陌生&#xff0c;如今的亚马逊市场也很多卖家都在用测评科技来打造爆款。不过很多对于亚马逊测评的认知只停留在简单的刷销量&#xff0c;上好评。殊不知亚马逊养号测评还有其它强大的骚操作。 亚马逊自养号测评哪些功能呢&#xf…

PyTorch 深度学习实战 |用 TensorFlow 训练神经网络

为了更好地理解神经网络如何解决现实世界中的问题&#xff0c;同时也为了熟悉 TensorFlow 的 API&#xff0c;本篇我们将会做一个有关如何训练神经网络的练习&#xff0c;并以此为例&#xff0c;训练一个类似的神经网络。我们即将看到的神经网络&#xff0c;是一个预训练好的用…

【深度学习】【分布式训练】Collective通信操作及Pytorch示例

相关博客 【深度学习】【分布式训练】Collective通信操作及Pytorch示例 【自然语言处理】【大模型】大语言模型BLOOM推理工具测试 【自然语言处理】【大模型】GLM-130B&#xff1a;一个开源双语预训练语言模型 【自然语言处理】【大模型】用于大型Transformer的8-bit矩阵乘法介…

第02章_变量与运算符

第02章_变量与运算符 讲师&#xff1a;尚硅谷-宋红康&#xff08;江湖人称&#xff1a;康师傅&#xff09; 官网&#xff1a;http://www.atguigu.com 本章专题与脉络 1. 关键字&#xff08;keyword&#xff09; 定义&#xff1a;被Java语言赋予了特殊含义&#xff0c;用做专门…

银河麒麟服务器ky10 sp3 x86 pgadmin使用

目录 打开网页并登录 连接数据库 备份数据库 还原数据库 打开网页并登录 打开浏览器&#xff0c;输入127.0.0.1:5050&#xff0c;输入用户名和密码登录&#xff0c; 我这边设置的用户名是123456qq.com&#xff0c;密码是 123456 连接数据库 右键选择register-Server 输…

Html5版飞机大战游戏中(Boss战)制作

内容在“60行代码&#xff0c;制作飞机大战游戏”的基础上&#xff0c;继续追加入了Boss战的功能。 boss的血量默认设置为100了&#xff0c;可以二次开发调整……(^_^) 玩起来有一定难度哈。 试玩地址&#xff1a;点击试玩 实现功能 添加玩家飞机&#xff0c;并进行控制Boss能…

vue+MapboxGL:从0 到1 搭建开发环境

本系列教程是在vue2.X的基础上加载mapbox 程序,来开发各种示例程序。 安装顺序 1,下载安装nodejs 下载地址:https://nodejs.org/en/download/ 根据用户自己的机器情况进行选择不同版本的软件下载。 本教程示例采用是是windows 64位系统软件。 安装过程很简单,一路下一步…

vue-router3.0处理页面滚动部分源码分析

在使用vue-router3.0时候&#xff0c;会发现不同的路由之间来回切换&#xff0c;会滚动到上次浏览的位置&#xff0c;今天就来看看这部分的vue-router中的源码实现。 无论是基于hash还是history的路由切换&#xff0c;都对滚动进行了处理&#xff0c;这里分析其中一种即可。 无…

TeeChart Pro ActiveX 2023.3.20 Crack

TeeChart Pro ActiveX 图表组件库提供数百种 2D 和 3D 图形样式、56 种数学和统计函数供您选择&#xff0c;以及无限数量的轴和 14 个工具箱组件。图表控件可以有效地用于创建多任务仪表板。 插件的多功能性 ActiveX 图表控件作为服务器端库中的 Web 图表、脚本化 ASP 图表或桌…

0201概述和结构-索引-MySQL

文章目录1 概述1.1 介绍1.2 优缺点2 索引结构2.1 BTree索引2.2 hash索引2.3 对比3 索引分类3.1 通用分类3.2 InnoDB存储引擎分类4 思考题后记1 概述 1.1 介绍 索引是帮忙MySQL 高效获取数据的数据结构&#xff08;有序&#xff09;。在数据之外&#xff0c;数据系统还维护着满…

【CF1764C】Doremy‘s City Construction(二分图,贪心)

【题目描述】 有nnn个点&#xff0c;每个点的点权为aia_iai​&#xff0c;你可以在任意两个点之间连边&#xff0c;最终连成的图需要满足&#xff1a;不存在任意的三个点&#xff0c;满足au≤av≤awa_u\le a_v\le a_wau​≤av​≤aw​&#xff08;非降序&#xff09;且边(u,v)(…

『pyqt5 从0基础开始项目实战』06. 获取选中多行table 重新初始化数据(保姆级图文)

目录导包和框架代码重新初始化绑定点击事件获取当前选中的所有行id实现初始化数据完整代码main.pythreads.py总结欢迎关注 『pyqt5 从0基础开始项目实战』 专栏&#xff0c;持续更新中 欢迎关注 『pyqt5 从0基础开始项目实战』 专栏&#xff0c;持续更新中 导包和框架代码 请查…