C++多态特性

news2025/1/10 16:05:49

在这里插入图片描述

🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨
🐻强烈推荐优质专栏: 🍔🍟🌯C++的世界(持续更新中)
🐻推荐专栏1: 🍔🍟🌯C语言初阶
🐻推荐专栏2: 🍔🍟🌯C语言进阶
🔑个人信条: 🌵知行合一
🍉本篇简介:>:讲解C++中多态知识,不同对象不同的处理方式.
金句分享:
✨不要总是抱怨环境,鼓起勇气战胜它!✨

前言

多态的概念:就是多种形态,当不同的对象去完成某个动作时会产生出不同的状态。

比如:在现实生活中,我们经常遇到不同身份的人享受的待遇不一样.

购买回家的火车票时,如果是购买的学生票,会有打折优惠.
在参加某宝,某团的活动时,新用户获得的优惠券就会比活跃用户的额度高不少.

C++中的多态(polymorphism)指的是同一个函数名在不同对象上可以有不同的行为。
它可以通过两种方式实现:
(1)虚函数(virtual function

虚函数是在基类中声明的函数,它可以被派生类重写,实现多态的效果。在派生类中实现的函数可以覆盖基类中的同名函数,而且会在运行时的对象类型上调用合适的函数。通过将基类指针或引用指向派生类对象,可以实现动态多态性。

(2)模板(template)。(前面已经讲过了)

模板是一种通用的代码库,可以为不同的类型提供相同的代码实现。使用模板可以实现静态多态性。在编译期间,编译器会依据模板中使用的类型,生成适当的代码。

使用多态可以让代码更加灵活,易于维护和扩展。此外,多态也是对象导向程序设计中的核心概念之一。

目录

  • 前言
  • 一、多态的实现
    • 🍭实现多态的条件:
  • 二、何为虚函数?
    • 🍉就你小子特殊?
    • 2.1 析构函数可以是虚函数吗?
  • 三、 关键字override 和 final

一、多态的实现

代码1,2,3的执行结果是什么?

class People
{
public:
    void Have_lunch()
    {
        cout << "你需要支付10元的午餐费!" << endl;
    }
};

class Student:public People
{
public:
    void Have_lunch()
    {
        cout << "你需要支付8元的午餐费!" << endl;
    }
};

class Teacher:public People
{
public:
    void Have_lunch()
    {
        cout << "老师,您好,欢迎就餐!已扣除5元餐费." << endl;
    }
};

void test1(People& p1)
{
    p1.Have_lunch();
}

int main()
{
    People p1;
    Student s1;
    Teacher t1;

    test1(p1);	//1
    test1(s1);	//2
    test1(t1);	//3
    return 0;
}

在这里插入图片描述
运行结果:

你需要支付10元的午餐费!
你需要支付10元的午餐费!
你需要支付10元的午餐费!

在前面的继承章节,我们知道,基类和派生类是两个不同的作用域,定义同名的两个函数时,会形成隐藏操作.所以这里的打印结果都是一样的.

如果想实现态,也就是不同的对象调用同一个函数,实现不同的结果,以下代码就是实现的例子,试着观察一下区别吧.
在这里插入图片描述

运行结果:

你需要支付10元的午餐费!
你需要支付8元的午餐费!
老师,您好,欢迎就餐!已扣除5元餐费.

🍭实现多态的条件:

  1. 继承关系:多态需要通过继承关系来实现,子类必须要继承父类。

  2. 方法重写(虚函数实现):子类必须重写父类的方法,这样才能表现出不同的行为。

  3. 父类指针/引用指向子类对象:必须是父类的指针或者引用调用虚函数,才能进行多态操作。

二、何为虚函数?

C++中的虚函数是一种特殊的成员函数,用于在继承关系中实现多态性。在父类中通过关键字virtual声明的函数为虚函数,子类可以覆盖并重新实现(重写)该函数。当通过父类的指针或引用调用虚函数时,实际调用的是子类中的实现,而不是父类的实现。这样就实现了多态.

普通函数:

	virtual void Have_lunch()
	{
		cout << "你需要支付8元的午餐费!" << endl;
	}

虚函数:

	virtual void Have_lunch()
	{
		cout << "你需要支付8元的午餐费!" << endl;
	}

虚函数的重写要求十分严格:

  1. 返回类型要相同:
    在这里插入图片描述
  2. 参数类型要相同:
    在这里插入图片描述
  3. 函数名相同:这个就不演示了,肯定无法实现多态.

🍉就你小子特殊?

虚函数的特殊情况: 斜变

派生类重写基类虚函数时,与基类虚函数返回值类型不同。
基类虚函数返回基类对象的指针或者引用.
派生类虚函数返回派生类对象的指针或者引用时.
这种情况,即使返回值不同,此时也满足虚函数的重写,也可以实现多态.

//斜变
class People
{
public:
	virtual People* Have_lunch()		//返回基类的指针或者引用
	{
		cout << "你需要支付10元的午餐费!" << endl;
		return nullptr;
	}
};

class Student :public People
{
public:
	virtual Student* Have_lunch()		//返回派生类的指针或者引用
	{
		cout << "你需要支付8元的午餐费!" << endl;
		return nullptr;
	}
};

class Teacher :public People
{
public:
	virtual Teacher* Have_lunch()		/返回派生类的指针或者引用
	{
		cout << "老师,您好,欢迎就餐!已扣除5元餐费." << endl;
		return nullptr;
	}
};

运行结果:
在这里插入图片描述

2.1 析构函数可以是虚函数吗?

显然,基类与派生类析构函数的名字不同 .

看起来违背了重写的规则,其实不然,这里可以理解为编译器对析构函数的名称做了特殊处理,编译后析构函数的名称统一处理成destructor。即所有对象的析构函数,在编译后,都被处理为统一的名字:destructor.

在这里插入图片描述

  1. 为什么析构函数名要被统一转化为destructor?

因为要实现多态需要函数名相同.

  1. 为什么析构函数要实现多态?

因为析构函数实现多态了以后,才能实现在析构基类和派生类时,各自调用自己的析构函数,防止内存泄漏!

示例:

class People
{
public:
	 ~People()
	{
		free(arr);
		cout << "~People()" << endl;
	}
private:
	int* arr = new int[10];		
};

class Student :public People
{
public:
	~Student()
	{
		free(arr2);
		cout << "~Student()" << endl;
	}
private:
	int* arr2 = new int[10];
};


int main()
{
	People* p1 = new People;		
	People* p2 = new Student;		//基类指针指向派生类

	delete p1;
	delete p2;		//arr2未释放
	return 0;
}

运行结果:

在这里插入图片描述
显然,在未实现多态的情况下,当基类指针指向派生类时,调用析构函数都只能调用基类的析构函数.这就导致了派生类存在成员变量并没有释放空间,也就导致了内存泄漏!

在这里插入图片描述
综上,析构函数可以是虚函数,而且还强烈建议将析构函数写成虚函数,实现多态.

虚函数重写需要遵守以下条件:

  1. 函数名称、参数列表和返回类型在父类和子类中必须完全相同。(三同)
  2. 函数在父类中必须被声明为virtual关键字,否则在子类中重写将不会产生多态效果。
  3. 函数在子类中必须使用virtual关键字进行声明,以便在运行时确定需要调用的是哪个版本的函数。

三、 关键字override 和 final

先声明一下:
这两个关键字是c++11才出现的,老版本不支持哦!

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

很多时候,我们需要实现多态,但是由于一时疏忽,将函数名写错了一个字母,或者返回值,参数列表等不同,而导致无法进行虚函数的重写.

class People
{
public:
	 virtual void Have_lunch()
	{
		cout << "你需要支付10元的午餐费!" << endl;
	}
};

class Student :public People
{
public:
	virtual void Have_Lunch()override
	{
		cout << "你需要支付8元的午餐费!" << endl;
	}
};

class Teacher :public People
{
public:
	 void Have_lunch()override
	{
		cout << "老师,您好,欢迎就餐!已扣除5元餐费." << endl;
	}
};

在这里插入图片描述

有的时候,我们并不像函数成为虚函数,又担心自己不小心满足了虚函数的重写的条件.(其实,博主感觉这种情况很少,也可能是博主目前接触的代码还比较少,没体会到.😂)

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

class People
{
public:
	 virtual void Have_lunch()final
	{
		cout << "你需要支付10元的午餐费!" << endl;
	}
};

class Student :public People
{
public:
	virtual void Have_lunch()
	{
		cout << "你需要支付8元的午餐费!" << endl;
	}
};

在这里插入图片描述

对于多态,本文就介绍到这里了,多态的实现原理是什么?菱形继承搭配虚拟继承会不会很头痛?
想要更加深层的理解C++的多态,下一篇文章,咱们不见不散!
在这里插入图片描述

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

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

相关文章

C++进阶-STL queue容器的简单认识

STL queue容器的简单认识 queue容器的基本概念queue容器的构造函数queue容器的赋值操作queue容器的数据存取queue容器的大小操作 queue容器的基本概念 queue是一种 先进先出 (First In First Out, FIFO)的数据结构&#xff0c;它有两个出口 队列容器允许从一端新增元素&#…

Azure 机器学习 - 如何使用模板创建安全工作区

目录 先决条件了解模板配置模板连接到工作区疑难解答错误&#xff1a;Windows 计算机名的长度不能超过 15 个字符&#xff0c;并且不能全为数字或包含以下字符 本教程介绍如何使用 [Microsoft Bicep]和 [Hashicorp Terraform]模板创建以下 Azure 资源&#xff1a; Azure 虚拟网…

【chat】4: ubuntu20.04:数据库创建:mysql8 导入5.7表

【chat】3: ubutnu 安装mysql-8 并支持远程访问 已经支持 8.0的SQLyog 远程访问:大神2021年的文章:sql是5.7的版本,我使用的ubuntu20.04,8.0版本:chat数据库设计 C++搭建集群聊天室(七):MySQL数据库配置 及项目工程目录配置 User表,以id 唯一标识 Friend 表,自己的id…

Run highlighted commands using IDE

背景 有时候在 IEDE 的命令行中输入命令&#xff0c;会弹出如下提示&#xff0c;或者命令被着了背景色了&#xff0c;是怎么回事&#xff1f; 其实就是提示你可以使用 IDEA 的功能替代命令行。比如使用ctrlenter或cmdenter之后使用的就是 IDEA 里的功能 直接enter运行&#x…

YOLOv5改进 | 添加CA注意力机制 + 增加预测层 + 更换损失函数之GIoU

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。在小目标场景的检测中&#xff0c;存在远距离目标识别效果差的情形&#xff0c;本节课提出一种基于改进YOLOv5的小目标检测方法。首先&#xff0c;在YOLOv5s模型的Neck网络层融合坐标注意力机制&#xff0c;以提升模型的特…

HTML点击链接强制触发下载

常见网页中会有很多点击链接即下载的内容&#xff0c;以下示范一下如何实现 <a href"文件地址" download"下载的文件名字&#xff08;不包括后缀&#xff09;">强制下载</a> 下面举个例子&#xff1a; <a href"./image/test.jpg"…

【我悟了】异常断电导致的文件系统变为只读——案例分析

背景 应领导要求&#xff0c;临时支持其他项目上遇到的一个问题。由于该问题属于未涉及的知识领域&#xff0c;从接触到最终给出方案&#xff0c;也花了我不少精力。在此进行分享&#xff0c;主要介绍在面对不熟悉的问题领域时&#xff0c;分析问题的思路。希望能够给年轻的同学…

小心你的大模型被基准评估坑了,模型直接傻掉!人大高瓴揭秘大模型作弊

作者 | 谢年年、Python 从 ChatGPT 横空出世到国内外「百模大战」打响以来&#xff0c;我们隔三差五就会看到某某大模型又超越多个模型&#xff0c;刷新SOTA&#xff0c;成功屠榜的消息。 这些榜单都是基于一系列高质量的评估基准创立的&#xff0c;从不同的方面比较LLMs的性能…

【VastbaseG100】 The password has been expired, please change the password.

NOTICE: The password has been expired, please change the password. vsql ((Vastbase G100 V2.2 (Build 10) Release) compiled at 2022-09-18 13:48:47 commit 9104 last mr ) 非SSL连接&#xff08;安全性要求高时&#xff0c;建议使用SSL连接&#xff09; 输入 "h…

xss 盲打

XSS 盲打 为什么教盲打&#xff0c;是因为处于被动&#xff0c;要等待受害者触发 1.利用存储型XSS 先将代码写入留言。同时kali开启端口监听&#xff08;下面IP是kali的&#xff09; <script>document.write(\<img src\"http://10.9.47.79/\document.cookie\\&qu…

Python开源项目RestoreFormer(++)——人脸重建(Face Restoration),模糊清晰、划痕修复及黑白上色的实践

有关 python anaconda 及运行环境的安装与设置请参阅&#xff1a; Python开源项目CodeFormer——人脸重建&#xff08;Face Restoration&#xff09;&#xff0c;模糊清晰、划痕修复及黑白上色的实践https://blog.csdn.net/beijinghorn/article/details/134334021 1 RESTOREF…

3.1 IDA Pro编写IDC脚本入门

IDA Pro内置的IDC脚本语言是一种灵活的、C语言风格的脚本语言&#xff0c;旨在帮助逆向工程师更轻松地进行反汇编和静态分析。IDC脚本语言支持变量、表达式、循环、分支、函数等C语言中的常见语法结构&#xff0c;并且还提供了许多特定于反汇编和静态分析的函数和操作符。由于其…

程序员的护城河:技术、创新与软实力的完美融合

作为IT行业的从业者&#xff0c;我们深知程序员在保障系统安全、数据防护以及网络稳定方面所起到的重要作用。他们是现代社会的护城河&#xff0c;用代码构筑着我们的未来。那程序员的护城河又是什么呢&#xff1f;是技术能力的深度&#xff1f;是对创新的追求&#xff1f;还是…

Linux 基于 LVM 逻辑卷的磁盘管理【简明教程】

一、传统磁盘管理的弊端 传统的磁盘管理&#xff1a;使用MBR先对硬盘分区&#xff0c;然后对分区进行文件系统的格式化最后再将该分区挂载上去。 传统的磁盘管理当分区没有空间使用进行扩展时&#xff0c;操作比较麻烦。分区使用空间已经满了&#xff0c;不再够用了&#xff…

Linux系统初步了解

Linux系统由4个主要部分组成&#xff1a;内核、Shell、文件系统和应用程序。 本专题主要是围绕这四个来展开的。 POSIX&#xff08;可移植操作系统接口&#xff09;定义了操作系统应该为应用程序提供的标准接口&#xff0c;其意愿是获得源码级别的软件可移植性。所以Linux选择…

程序员的那些坏习惯!来看看你有几个?

一、前言 写了20多年代码&#xff0c;我见过不下于4位数的程序员&#xff0c;我觉得程序员的能力水平可以分为4个阶段&#xff1a;线性级、逻辑级、架构级和工程级。 同样的在这些人当中&#xff0c;我也发现了8个程序员最常见的陋习&#xff0c;基本上可以覆盖90%的人&#…

高德资深技术专家孙蔚:海量用户应用数据库选型、升级实践

高德地图&#xff08;以下简称“高德”&#xff09;作为一款用户出行必备、拥有海量用户数据的导航软件&#xff0c;对系统运行稳定性要求极高。 一直以来&#xff0c;高德每时每刻都在生产的一些数据库中的数据已经达到数百 TB&#xff0c;数据量的增长不仅带来存储成本的迅速…

关于Office阻止访问嵌入对象的解决办法

问题 Word文档中想要下载嵌入的文件时被Office阻止了&#xff0c;无法下载。 解决办法 打开文件——选项——信任中心&#xff0c;在宏设置中启用所有宏&#xff0c;关于Macro、Acitve X插件等项目设置上&#xff0c;建议暂时全部设置为允许&#xff0c;看下相关对象的访问…

try-catch-finally执行以及他们在有return的情况下,基本数据类型、对象以及有异步赋值情况异同分析

这两天面试,遇到好几个人,都是那种我感觉我肚子里的墨水都吐出来完了,难不倒人家,于是问了下家里那位老狗,从最开始就念叨着你问他try-catch在有return的情况下怎么执行的,执行结果是啥,我前面没理,后面确实有点遭不住了,来看看吧,肚子里添点墨水,别把脸丢大了~ 做…

分布式搜索引擎ES

文章目录 初识elasticsearch了解ES倒排索引正向索引倒排索引正向和倒排 es的一些概念文档和字段索引和映射mysql与elasticsearch 安装ES部署kibana安装IK分词器扩展词词典停用词词典 索引库操作mapping映射属性索引库的CRUD创建索引库和映射查询索引库修改索引库删除索引库 文档…