C++三大特性之一:多态篇【创作不易,还请点赞+收藏❤】

news2024/12/28 19:32:46

一、多态的概念

  • 从我们学习C++的时候,想必或多或少都听说过,C++的三大特性:封装、继承,多态;而今天我们将学习多态,多态简单来讲,就是多种形式
  • 多态分为,编译时多态——静态多态,运行时多态——动态多态。
  • 静态多态:主要是函数重载和模板,在编译的时候,通过传递的参数不同,确定调用的具体某一种形式,因为是在编译时确定的,所以又称为编译时多态。
  • 动态多态:子类与父类具有函数原型(函数名,返回参数,参数类型与个数)相同的虚函数,则在运行的时候,子类对象,通过调用基类的指针或引用,调用的子类的虚函数。举个现实的例子——在现实生活中,各地景点的购票窗口,不同的对象去买票,会存在不同的购票政策。如果是一个普通的成年人去购票,只能全价购票,若是一个大学生去购票,则允许半价购票,倘若你是一个军人,售票窗口可以为你,提供一个优先购票的车道。而不同的对象(买票的不同群体)去调用相同的函数(同一个售票窗口),可实现不同的效果。
  • 最常用的多态,是通过虚函数实现的多态——动态动态★★★

二、多态的定义与实现

1.多态的构成条件

  • 多态的是一个继承关系下的类对象,去调用同一函数,而产生了不同的行为。
  • 子类与父类具有函数原型相同的函数,且两个函数必须是虚函数。
  • 必须是通过基类的指针或引用调用的虚函数。
  • 说明:父类的指针或引用可以同时指向父类对象、子类对象(通过父子类之间的类型兼容赋值,是一种切片效果)。子类必须对父类的虚函数重写/覆盖,只有这样,父子类才能有不同的虚函数,多态的不同效果才能达到。 
class Adult
{
public:
	void Buy_Ticket()
	{
		cout << "郑州方特欢乐世界:180¥" << endl;
	}

	virtual void Service() 
	{
		cout << "请排队购票,原价——180¥" << endl;
	}
};

class Student : public Adult
{
public:
	virtual void Service()
	{
		cout << "请排队购票,学生价——90¥" << endl;
	}
};

class Soldier : public Adult
{
public:
	virtual void Service()
	{
		cout << "退役或现役军人,可优先购票,原价——180¥" << endl;
	}
};

void test(Adult& per) 
{
	per.Buy_Ticket();
	per.Service();
	cout << endl;
}

int main()
{
	// 多态构成条件之一:基类的指针或引用
	// 多态构成条件之二:父子类函数原型相同,且都是虚函数。

	Adult per1;
	Student per2;
	Soldier per3;

	test(per1);
	test(per2);
	test(per3);

	return 0;
}

2.虚函数

        虚函数的定义:在非静态成员函数声明的前面加上关键字virtual,切记,虚函数只能用于成员函数中,其次static与关键字virtual不能同时使用。

3.重写/覆盖

       (1)子类与父类具有相同的虚函数(返回参数、函数名、函数参数都相同),而函数体的内容不同,则可以说明子类重写了父类的虚函数。

       (2)父类成员函数+virtual,而子类成员函数没有+virtual的时候,因为子类继承了父类的原因,子类的函数,也具有虚函数的性质。所以父子类成员函数原型相同,父类的成员函数+virtual,而子类的成员函数没有加virtual,也构成重写。

        (3)考察重写知识点的一种常见的坑,请分析下面的源代码,猜想一下其运行结果是什么?另外补充一些疑问:
        子类的,func()前面未有virtual关键字,且其参数虽类型相同,但变量名称却不相同,父子类的func()是否构成虚构函数?
        p->test(),在调用父类中的test()函数,会传递p的地址,给this指针,请问this指针的类型是A*,还是B*?                                                                                                                                                 答案选项:A: A->0 B: B->1 C: A->1 D: B->0 E: 编译出错 F: 以上都不正确。

        想必各位同学心中已经有了自己的答案,下面开始解析这道代码题:

        问1:子类的,func()前面未有virtual关键字,且其参数虽类型相同,但变量名称,以及其缺省值却不相同,父子类的func()是否构成虚构函数?
        答1:构成虚函数。首先继承父类的时候,对于普通成员函数来讲,可能继承函数的实现,而对于虚函数来讲,继承的是其函数声明(virtual func(int)),而子类对父类虚函数的重写,仅仅是修改父类的函数体的实现。所以子类重写的虚函数前面不加virtual,以及参数变量名不同,也不管缺省值是否相同,但只要保证参数类型相同,个数相同即可。

        问2:p->test(),在调用父类中的test()函数,会传递p的地址,给this指针,请问this指针的类型是A*,还是B*?  
        答2:A*,在C++中成员函数的this指针的类型,是由函数定义的时候就已经确定好的,与调用对象的具体类型是无关系的。

        问3:嗯,我明白了,p->test(),会构成多态,通过父类的指针调用到了子类的虚函数,但是输出结果为什么是B->1,而不是B->0呢?你看子类的虚函数func的缺省值是0。                                      答3:在问题1的回答中,我已经提到,子类继承父类虚函数的时候,是对其接口进行继承,当子类重写父类的虚函数时,它实际上是在提供一个新的函数实现,而不是改变函数的原型,所以就不存在重写父类的函数参数默认值。

4.析构函数的重写

        讲这个知识点之前,先来看一下代码案例,请问下面这个代码的运行结果是否是正确的?

class A
{
public:
	~A()
	{
		cout << "~A()" << endl;
	}
};

class B : public A
{
public:
	~B()
	{
		cout << "~B()" << endl;
	}
private:
	int* Data = new int[10];
};

        经过代码分析与程序运行可得,这个代码的运行具有安全问题,存在内存泄漏问题,当释放val对象的时候,仅仅是调用了父类的析构函数,而没有对子类的资源进行清理。

        为了解决这一问题,C++让子类可以重写父类的析构函数。既然子类可以重写父类的析构函数,可以推出:父类与子类的析构函数应该满足函数名相同、返回值相同、函数参数相同。而编译器的处理也是能印证我们的猜想,对象的析构函数的函数名,都会被编译器认为是destructor。

        下面是重写父类析构函数之后,再次运行代码,正确的运行结果:

5..协变

        继承体系中,成员函数重写有一种特殊的形式,两个虚函数的返回值可以不同,只要满足父类的虚函数的返回值是父类的指针或引用,子类的虚函数的返回值是子类的指针或引用(两者虚函数的返回值应该构成父子类关系)。

        这种特殊的重写形式,被称为协变~

class Person
{
public:
	virtual Person* func() // 返回是父类的指针或引用
	{
		cout << " Person : void func()" << endl;
		return nullptr;
	}
};

class ZMH : public Person
{
public:
	virtual ZMH* func() // 返回是子类的指针或引用
	{
		cout << " ZMH : void func()" << endl;
		return nullptr;
	}
};

int main()
{
	Person* pa = new Person;
	Person* pb = new ZMH;

	pa->func();
	pb->func();

	return 0;
}

6.关键字override的使用

        在继承体系中,多态的构成条件之一,父子类的虚函数构成重写的要求相对严苛(函数名相同,参数相同,返回值相同或构成协变),比如:函数名拼写错误则就构不成重写,且经常是出自运行中报错,如果在运行中,得不到我们想要的正确结果,再去debug,难免会造成一些时间的消耗。(比如把上面的例子进行修改,再次运行的结果是得不到我们的要求的,且编译的时候也不会报错。)

        所以C++11,引入了override关键字(汉语意思是重写),override关键字,用于要重写函数的函数参数后面;这个关键字的意图是在告诉编译器,帮我检查一下,在子类重写的父类函数的时候,是否满足重写的语法规则,则不满足重写的语法规则,则会报错。

7.关键字final的使用

        这里将扩展一下关键字final的用途,在继承篇中,我们已经了解到,final关键字是用来实现一个不可继承的类;而在多态中,final则可以用在虚函数中,而不再让子类进行重写。

8.纯虚函数与抽象类

class  Base // 包含虚函数的类,被称为抽象类
{
    virtual void func() = 0; // 虚函数的书写形式
};

        (1)纯虚函数的定义:诚如上述的,Base::func()的例子,在其函数声明后面加上“ = 0 ”,则此函数则被称为纯虚函数;纯虚函数必须被重写或者覆盖之后才能使用。

        (2)抽象类的定义:包含纯虚函数的的类,则被称为抽象类,抽象类不能实例化出对象,但可以被派生类继承,若派生类,没有重写该纯虚函数,则派生类,则仍为抽象类。

        (3)注意事项:在C++语法上,纯虚函数的实现是没有实际意义的,但并不代表就不能实例化,这一点在考试中,经常作为选项迷惑考生。

        (4)下面用纯虚函数写一个简单的代码~,帮助理解纯虚函数与抽象类。

class Animal
{
public:
	// 此函数接口是用来,用程序打印字符串来,描述动物的叫声
	// 但此Animal并不是具体的对象,所以用此接口设计为纯虚函数,此类设计为抽象类
	virtual void Animal_voice() = 0; 
	static void func(Animal* animal)
	{
		animal->Animal_voice();
	}
};

class Cat:public Animal
{
public:
	
	virtual void Animal_voice() final // Cat是一个具体的对象的类型,这里用final关键字
	{
		cout << " 喵~喵~喵~" << endl;
	}
};


class Dog :public Animal
{
public:

	virtual void Animal_voice() final // Dog是一个具体的对象的类型,这里用final关键字
	{
		cout << " 汪~汪~汪~" << endl;
	}
};

int main()
{
	Cat animal1;
	Dog animal2;

	Cat::func(&animal1);
	Dog::func(&animal2);

	return 0;
}

三、重载、隐藏以及重写的总结

        重载、隐藏、以及重写因其条件的相似性,如果不及时区分清楚,可能会为我们之后的编程学习带来不上的迷惑,下面就让我来为其作一个小小的终结,还请笑纳~

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

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

相关文章

Spark-ShuffleWriter-UnsafeShuffleWriter

一、上下文 《Spark-ShuffleWriter》中对ShuffleWriter的获取、分类和写入做了简单的分析&#xff0c;下面我们对其中的UnsafeShuffleWriter做更详细的学习 二、构建UnsafeShuffleWriter public UnsafeShuffleWriter(BlockManager blockManager,TaskMemoryManager memoryMana…

利用Packet tracer搭建简单的网络并进行通信验证

利用Packet tracer搭建一个基本的网络通信&#xff1a; 1&#xff1a;创建网络组件 先去创建几个终端设备&#xff0c;然后再去创建一个交换机 布局完成的界面是&#xff1a; 2&#xff1a;连接组件 用指定的线进行连接交换机和PC机 全部连接的结果是: 3&#xff1a;配置PC机…

桥接网络设置多用户lxd容器

文章目录 前言配置宿主机网络固定内核版本安装 lxd、zfs 及 bridge-utils安装宿主机显卡驱动lxd 初始化创建容器模板安装容器显卡驱动复制容器 前言 使用桥接网络配置 lxd 有个好处&#xff0c;就是每个用户都可以在该局域网下有一个自己独立的 IP&#xff0c;该 IP 的端口可以…

崩坏星穹铁道PC端2.5版本剧情、奖励攻略 用GameViewer远程帮手机减负 随时畅玩星铁PC端

《崩坏&#xff1a;星穹铁道》2.5版本「碧羽飞黄射天狼」在9月10开启&#xff01;上半卡池有五星角色飞霄、知更鸟、卡芙卡、黑天鹅四位角色&#xff0c;还有2.5版本的新剧情&#xff0c;这一次崩铁上线送10连和 1000星琼等其他材料。由于游戏包体过大&#xff0c;不少玩家都选…

web群集--nginx实现重定向与重写操作的详细配置过程详与案例展示

文章目录 前言什么是重定向&#xff1f;重定向能做什么&#xff1f;何时需要重定向功能&#xff1f;nginx通过什么来实现重定向和重写操作的&#xff1f;nginx的重定向和重写有什么区别&#xff1f;案例展示重定向1.将所有对将所有对http://test. com 的访问重定向到http://www…

【iOS】push和present的区别

【iOS】push和present的区别 文章目录 【iOS】push和present的区别前言pushpop presentdismiss简单小demo来展示dismiss和presentdismiss多级 push和present的区别区别相同点 前言 在iOS开发中&#xff0c;我们经常性的会用到界面的一个切换的问题&#xff0c;这里我们需要理清…

眼镜超声波清洗机真的有用吗?畅销款热门清洗机测评,买前必看!

随着科技的飞速发展&#xff0c;人们的生活水平也日益提升。眼镜&#xff0c;作为我们日常生活中不可或缺的物品&#xff0c;其重要性不言而喻。然而&#xff0c;许多人往往忽视了对它的定期清洁保养。尽管市面上有专门用于清洁眼镜的布&#xff0c;但这种方法并不能完全去除镜…

CloudFlare问题与CDN问题

昨天将腾讯云的解析转移到Cloudflare中了&#xff0c;结果今天发现网站崩了&#xff0c;显示重定向次数过多&#xff0c;昨天估计是因为浏览器缓存&#xff0c;所以没有发现问题 问题一&#xff1a;强制HTTPS 当时看到CloudFlare的强制https时就想到了我的宝塔面板也开着强制h…

【机器学习】结构学习的基本概念以及基于约束的结构学习和基于评分的结构学习

引言 结构学习在机器学习中是指自动发现数据中潜在的结构或模式的过程&#xff0c;这通常涉及到确定数据的依赖关系、变量间的相互作用或者数据的组织形式。 文章目录 引言一、结构学习1.1 目标1.2 方法1.3 应用1.4 挑战1.5 工具和技术1.6 步骤1.7 总结 二、基于约束的结构学习…

2024年法国7大最佳影响力营销平台

影响力平台是一种工具&#xff0c;可以帮助企业找到有影响力的人&#xff0c;全面管理从头到尾的营销活动&#xff0c;并评估其效果。这类工具能够为广告商或影响力代理机构提供以下服务&#xff1a; 发布营销活动&#xff0c;让 有影响力的人可以申请。这就是所谓的 影响力市…

QT程序的安装包制作教程

在Windows平台上开发完qt c桌面应用程序以后&#xff0c;需要制作一个安装包&#xff0c;方便生产和刻盘交货&#xff0c;本文记录相关流程。 目录 一、安装Qt Installer Framework 二、准备可执行程序 2.1 生成Release程序 2.2 完成依赖库拷贝 三、创建安装包程序 一、…

2024icpc江西:H.Convolution(二维前缀和,卷积核)

题目 做法 我们发现&#xff0c;K中的每个元素都乘了对应原矩阵中子矩阵&#xff08;n-k1&#xff09;* (m-l1)中的每个数。我们就直接前缀和求就好了。 #include<bits/stdc.h> #define int long long using namespace std;const int N1e310; int n,m,k,l; int a[N][N…

语言中的浮点数

浮点数相比定点数或者整数&#xff0c;为了处理小数点引入了指数&#xff0c;导致小数点的位置根据不同浮点数而不同&#xff0c;故名为Floating Point Number. 一般而言&#xff0c;IEEE754标准被大部分编程语言的浮点数使用&#xff0c;它节省了浮点数的保存空间。如不然&…

思维导图模板,看完这些步骤学会制作

思维导图模板&#xff0c;思维导图是一种非常有效的信息组织工具&#xff0c;它将复杂的信息以图形化的形式展现出来&#xff0c;便于记忆和理解。无论是用于项目管理、学习笔记整理还是头脑风暴会议记录&#xff0c;思维导图都能够帮助人们更好地梳理思路&#xff0c;提高工作…

在 ClickHouse 中进行机器学习数据建模

本文字数&#xff1a;17443&#xff1b;估计阅读时间&#xff1a;44 分钟 作者&#xff1a;Dale McDiarmid 本文在公众号【ClickHouseInc】首发 本文将探索 MLOps 的世界&#xff0c;探讨如何在 ClickHouse 中对数据进行建模和转换&#xff0c;使其成为高效的特征存储&#xff…

百收网AI发帖子怎么发?

百收网AI发帖子怎么发&#xff1f; 百家号APP怎么发内容&#xff1f;没有电脑怎么在百度发内容&#xff1f;#百家号 查看视频讲解&#xff1a;&#xff08;点击链接https://v.youku.com/v_show/id_XNjQyMjc4MjU3Ng.html&#xff1a;https://v.youku.com/v_show/id_XNjQyMjc4M…

Linux云计算 |【第三阶段】PROJECT1-DAY1

主要内容&#xff1a; 服务器硬件&#xff08;RAID磁盘阵列、IDRAC远程控制卡&#xff09;、部署LNMP动态网站&#xff08;部署LNMP平台、上线Wordpress代码、创建数据库、初始化Wordpress&#xff09; 一、服务器介绍 1、什么是服务器 服务器&#xff08;Server&#xff09…

C++入门(part 3)

前言 在前文我们讲解了C的诞生与历史&#xff0c;顺便讲解一些C的小语法&#xff0c;本文会继续讲解C的基础语法知识。 1.inline(内联函数) inline是C新加入的关键字,用inline修饰的函数叫做内联函数&#xff0c;编译时C编译器会在调用的地方将函数展开&#xff0c;这样每次…

数据中台 | 数据资源管理平台介绍

01 产品概述 数据资源的盘查、集成、存储、组织、共享等全方位管理能力&#xff0c;无论对于企业的数字化转型&#xff0c;还是对企业数据资产的开发、运营、交易及入表&#xff0c;都具有极为关键的作用。今天&#xff0c;小兵就来为大家介绍我们自研数据智能平台中的核心产品…

废品回收小程序搭建,回收市场的机遇

随着经济的快速发展&#xff0c;居民生活水平普遍提高&#xff0c;产生的各类废品也在不断增加&#xff0c;为废品回收市场提供了发展基础。当下&#xff0c;在大众环保意识增加下&#xff0c;废品回收行业也将成为一个具有广阔发展前景的朝阳行业&#xff01; 目前&#xff0…