C++ 多态性

news2024/11/17 14:18:28

在这里插入图片描述

一 多态性的分类

编译时的多态
函数重载
运算符重载
运行时的多态
虚函数

1 运算符重载的引入

使用C++编写程序时,我们不仅要使用基本数据类型,还要设计新的数据类型-------类类型。

一般情况下,基本数据类型的运算都是运算符来表达,这很直观,语义也简单。

例如:

int a,b,c;a=b+c;

对于基本数据类型,就隐含着运算符重载的概念。

在这里插入图片描述
在这里插入图片描述
如果直接将运算符作用在类类型之上,情况又如何呢?
例如:

Complex ret,c1,c2;ret=c1+c2;

编译器将不能识别运算符的语义。
需要一种机制来重新定义运算符作用在类类型上的含义。
这种机制就是运算符重载。

二 两种重载函数的比较

多数情况下,运算符可以重载为类的成员函数,也可以重载为友元函数。但两种重载也有各自特点:
一般情况下,单目运算符重载为类的成员函数;双目元素重载为类的友元函数。
有些双目运算符不能重载为类的友元函数:=,(),[],->
类型转换函数只能定义为类的成员函数,而不能定义为友元函数。
若一个运算符的操作需要修改对象的状态,则重载为成员函数比较好;
若运算符所需要的操作数(尤其是第一个操作数)希望有隐式类型转换,则只能选择友元函数;
若运算符是成员函数,最左边的操作数必须是运算符类的对象(或者类对象的引用)。如果左边操作数必须是一个不同类的对象,或者是基本数据类型,则必须重载为友元函数;
当需要重载运算符的元素具有交换性时,重载为友元函数;

1 重载运算符的几点注意事项

大多数预定义的运算符可以被重载,重载后的优先级、结合级及所需的操作数都不变。
但少数的C++运算符不能重载:
例如:::、#、?:、.、
不能重载非运算符的符号,例如:;
C++ 不运行重载不存在的运算符,如"?"、“**”等。

当运算符被重载时,它是被绑定在一个特定的类类型之上的。当此运算符不作用在特定类类型上时,它将保持原有的含义。

当重载运算符时,不能创造新的运算符符号,例如不能用"**"来表示求幕运算符。

应当尽可能保持重载运算符原有的语义。试想,如果在某个程序中用"+“表示减,”*"表示除,那么这个程序读起来将会非常别扭。

三 多态性的引入

1 虚函数和多态性

重载普通的成员函数的两种方式:
在同一个类中重载:重载函数是以参数特征区分的。
派生类重载基类的成员函数:
由于重载函数处在不同的类中,因此它们的原型可以完全相同。调用时使用“类名::函数名”的方式加以区分。
以上两种重载的匹配都是在编译的时候静态完成的。

重载是一种简单形式的多态。
C++提供另一种更加灵活的多态机制:虚函数。虚函数运行函数调用与函数体的匹配在运行时才确定。
虚函数提供的是一种动态绑定的机制。

2 赋值兼容规则

在公有派生方式下,派生类对象可以作为基类对象来使用,具体方式如下:
在这里插入图片描述

派生类拥有从基类继承过来的成员;
基类对象和派生类对象的内存布局方式;
在这里插入图片描述
当一个派生类对象直接赋值给基类对象时,不是所有的数据都赋给了基类对象,赋予的只是派生类对象的一部分。这部分叫做派生类对象的“切片(sliced)”。

注意
回忆一下不同的继承方式,子类对基类中成员的访问权限:
在这里插入图片描述
只有在公有派生的情况下,才有可能出现“基类的公有成员变成派生类的公有成员”的情况。
在这里插入图片描述
通过基类引用或指针所能看到的是一个基类对象,派生类中的成员对于基类引用或指针来说是“不可见的”。

我们能不能“通过基类引用或指针来访问派生类的成员”呢?
为了达到上述目的,我们可以利用C++的虚函数机制,将基类的Print说明为虚函数形式。这样就可以通过基类引用或指针来访问派生类中的Print。

3 虚函数

在基类中用virtual关键字声明的成员函数即为虚函数。

虚函数可以在一个或多个派生类中被重写定义,但要求重定义时虚函数的原型(包括返回值类型、函数名、参数列表)必须完全相同。

3 基类中的函数具有虚特性的条件

在基类中用virtual将函数说明为虚函数。
在公有派生类中原型一致地重载该虚函数。
定义基类引用或指针,使其引用或指向派生类对象。当通过该引用或指针调用需要函数时,该函数将体现出虚特性来。

C++中,基类必须指出希望派生类重定义哪些函数。定义为virtual的函数是基类期待派生类重新定义的,基类希望派生类继承的函数不能定义为虚函数。

注意:
在派生类中重载虚函数时必须与基类中的函数原型相同,否则该函数将丢失虚特性。

仅返回类型不同,其他相同。C++编译器认为这种情况是不允许的。

函数原型不同,,仅函数名相同。C++编译器认为这是一般的函数重载,此时虚特性丢失。

四 虚函数与多态性

1 提供虚函数的意义

提升软件的重用性
基类使用虚函数提供一个接口,但派生类可以定义自己的实现版本。
虚函数调用的解释依赖于它的对象类型,这就实现了“一个接口,多种语义”的概念。
提供软件架构的合理性。

2 虚函数和虚指针

在编译时,为每个有虚函数的类建立一张虚函数表VTABLE,表中存放的时每一个虚函数的指针;同时用一个虚指针VPTR指向这张表的入口。
访问某个虚函数时,不是直接找到那个函数的地址,而是通过VPTR间接查到它的地址。

在这里插入图片描述
在这里插入图片描述
对象的内存空间除了保存数据成员外,还保存VPTR。VPTR由构造函数来初始化。

3 对虚函数的要求

虚函数必须是类的非静态成员函数。
不能将虚函数说明为全局函数。
不能将虚函数说明为静态成员函数。
不能将虚函数说明为友元函数。

本质的原因就是非静态成员函数隐含传递this指针,而通过this指针能够找到VPTR。

4 在成员函数中调用虚函数

在一个基类或派生类的成员函数中,可以直接调用类等级中的虚函数。此时需要根据成员函数中this指针所指向的对象来判断调用的时哪一个函数。

5 析构函数可以定义为虚函数

构造函数不能定义为虚函数。
而析构函数可以定义为虚函数。

若析构函数为虚函数,那么当使用delete释放基类指针所指向的派生类对象时,先调用派生类的析构函数,再调用基类的析构函数。

五 纯虚函数与抽象类

在这里插入图片描述

基类中的这些公共接口只需要有售卖而不需要有实现,即纯虚函数。纯虚函数刻画了派生类应该遵循的协议,这些协议的具体实现由派生类来决定。

在这里插入图片描述
将一个函数说明为纯虚hasn’t,就要求任何派生类都定义自己的实现。
拥有纯虚函数的类被称为抽象类。抽象类不能被实例化,只能作为基类被使用。
抽象类的派生类需要实现纯虚函数,否则该派生类也是一个抽象类。
当抽象类的所有函数成员都是纯虚函数时,这个类被称为接口类。

小结:
继承和动态绑定在两个方面简化了我们的程序:
能够容易地定义与其他类相似但又不相同的新类,能更容易地编写忽略这些相似类型之间区别的程序。

许多应用程序的特性可以用一些相关但略有不同的概率描述。面向对象编程与这种应用非常匹配。通过继承可以定义一些类型,可以模型不同冲类;通过动态绑定可以编写程序,使用这些类而又忽略与具体类型相关的差异。

继承和动态绑定的思想在概念上非常简单,但对于如何创建应用程序以及对于程序设计语言必须支持得特性,含义深远。

面向对象编程的关键思想是多态性。因为在需要情况下可以互换地使用派生类型或基类型的“许多形态”,所以称通过继承而相关联的类型为多态类型。C++中,多态型仅用于通过继承而相关性的类型的引用或指针。

我们称因继承而相关的类构成一个继承层次。其中一个类称为根,所有其他类直接或间接继承根类。

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

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

相关文章

识别公式的网站都有哪些?分享3个专业的工具!

在数字化时代,公式识别已成为一项重要技能。无论是学生、教师还是科研人员,都可能需要借助公式识别网站来快速准确地获取公式信息。那么,市面上到底有哪些值得一试的识别公式网站呢?本文将为您一一揭晓。 FUNAI FUNAI的公式识别功…

2024洗地机爆款榜单,哪个牌子洗地机值得买?助你轻松选对洗地机

随着现代生活节奏的加快,人们对于家庭清洁的需求也越来越高。家用洗地机作为一种高效清洁工具,能够帮助您轻松应对家庭地板的清洁问题,节省时间和精力。然而,在选择洗地机时,究竟哪个牌子的洗地机值得买呢?…

2024年网络安全岗位缺口已达100万,你该不会还不知道如何入门吧?

我发现最近安全是真的火,火到不管男女老少都想入门学一下。但是,要是真的问起他们,“你觉得网络安全是什么?为什么想学?”,十个人里不见得有一个人能逻辑清晰、态度坚定地回答出来。 作为一个时刻关注行业…

暗黑4可以搬砖吗?暗黑4怎么搬砖 搬砖攻略

暗黑4可以搬砖吗?暗黑4怎么搬砖 搬砖攻略 暗黑破坏神4属于是暴雪旗下一款经典游戏IP,在全世界有着广泛的玩家群体,更是在今年暴雪国服宣布回归之后,吸引了一大批新玩家加入。今天小编就为大家带来暗黑4的详细搬砖教程。 现在我们…

Leetcode—100296. 两个字符串的排列差【简单】

2024每日刷题&#xff08;135&#xff09; Leetcode—100296. 两个字符串的排列差 实现代码 class Solution { public:int findPermutationDifference(string s, string t) {int maps[26];int mapt[26];for(int i 0; i < s.size(); i) {int idxs s[i] - a;int idxt t[i…

服务器被后台爆破怎么处理

服务器后台遭受密码爆破攻击是网络安全中常见的威胁之一&#xff0c;这种攻击通过不断尝试不同的用户名和密码组合来破解系统登录凭证&#xff0c;一旦成功&#xff0c;攻击者便能非法访问系统资源。 本文将介绍如何识别此类攻击&#xff0c;并采取有效措施进行防御&#xff0c…

《四》系统模块整体功能关联与实现

在上一篇里&#xff0c;我们完成了动作的创建&#xff0c;那么这一次&#xff0c;我们把它加载到界面上&#xff0c;把需要是实现的动作都加上。 MyWord::MyWord(QWidget *parent): QMainWindow(parent) {mdiAreanew QMdiArea;mdiArea->setHorizontalScrollBarPolicy(Qt::S…

微信加粉计数器

1.采用非注入式开发&#xff0c;支持无限多开 2.每个账号都有独立的分组&#xff0c;实时远程网页数据分享 3.后台功能强大&#xff0c;操作简单&#xff0c;自动去重复&#xff0c;准确计数分秒不差

ubuntu使用交叉编译链编译FFTW动态库

一、从官方下载FFTW压缩包 1. 在 /usr/local 新建目录fftw目录&#xff0c; 将压缩包放在 /usr/local/fftw 中解压。 2.打开解压后的文件 导入环境变量&#xff1a; export PATH$PATH:/home/theer/workspace/a64/cqa64_linuxqt5.8_bv3s/buildroot-2017.02.3/output/host/…

C语言的打字小游戏

目录 游戏内容 伪代码 main 函数 随机字符串 匹配逻辑 用户决定是否继续或退出游戏 完整代码 从0开始记录我的学习历程&#xff0c;我会尽我所能&#xff0c;写出最最大白话的文章&#xff0c;希望能够帮到你&#xff0c;谢谢。 提示&#xff1a;文章作者为初学者&#xf…

HTML常用标签-布局相关标签

布局标签 div标签 俗称"块",主要用于划分页面结构,做页面布局 自己独占一行的元素&#xff0c;设置宽高生效 span标签 俗称"层",主要用于划分元素范围,配合CSS做页面元素样式的修饰 不会自己独占一行的元素&#xff0c;设置宽高不生效 代码 <div style&…

数据库SQL编写规范-SQL书写规范整理(SQL语句书写规范全解-Word原件)

编写本文档的目的是保证在开发过程中产出高效、格式统一、易阅读、易维护的SQL代码。 1 编写目 2 SQL书写规范 3 SQL编写原则 软件全套精华资料包清单部分文件列表&#xff1a; 工作安排任务书&#xff0c;可行性分析报告&#xff0c;立项申请审批表&#xff0c;产品需求规格说…

如何使用AzurEnum快速枚举Microsoft Entra ID(Azure AD)

AzurEnum是一款针对Azure的安全工具&#xff0c;在该工具的帮助下&#xff0c;广大研究人员可以轻松快速地枚举Microsoft Entra ID&#xff08;Azure AD&#xff09;。 该工具基于纯Python 3开发&#xff0c;可以在Windows和Linux系统上运行&#xff0c;但考虑到性能和稳定性&a…

iOS——runtime

什么是runtime 我们都知道&#xff0c;将源代码转换为可执行的程序&#xff0c;通常要经过三个步骤&#xff1a;编译、链接、运行。 C 语言 作为一门静态类语言&#xff0c;在编译阶段就已经确定了所有变量的数据类型&#xff0c;同时也确定好了要调用的函数&#xff0c;以及函…

数据库的存储过程、函数与触发器

使用下面的场景来引入 1.创建表 CREATE DATABASE staff; USE staff; CREATE TABLE employee(id INT NOT NULL AUTO_INCREMENT,userName VARCHAR(255),birthDate DATE,idCard VARCHAR(255),loginName VARCHAR(255),PASSWORD VARCHAR(255),mobile VARCHAR(255),email VARCHAR(2…

【综述】人工智能、机器学习、深度学习

文章目录 前言 概念 算法 训练 性能 应用 参考资料 前言 见《初试人工智能》 概念 人工智能系统&#xff08;artifieial intelligence system&#xff09;&#xff0c;针对人类定义的给定目标&#xff0c;产生诸如内容、预测、推荐或决策等输出的一类工程系统。该工程系…

MPEG-4 AVC/H.264高清编码器 JR3211P

概述 JR3211P MPEG-4 AVC/H.264高清编码器是一款专业的高清音/视频编码产品。该产品支持几乎所有模拟及数字音/视频输入接口&#xff0c;包括CVBS、YPbPr、S-video、SD/HD-SDI、HDMI视频输入接口、平衡模拟音频&#xff08;XLR&#xff09;、非平衡模拟音频&#xff08;RCA&am…

Qwen-VL环境搭建推理测试

引子 这几天阿里的Qwen2.5大模型在大模型圈引起了轰动&#xff0c;号称地表最强中文大模型。前面几篇也写了QWen的微调等&#xff0c;视觉语言模型也写了一篇CogVLM&#xff0c;感兴趣的小伙伴可以移步Qwen1.5微调-CSDN博客。前面也写过一篇智谱AI的视觉大模型&#xff08;Cog…

计算礼品发放的最小分组数目 - 贪心思维

系列文章目录 文章目录 系列文章目录前言一、题目描述二、输入描述三、输出描述四、java代码五、测试用例 前言 本人最近再练习算法&#xff0c;所以会发布自己的解题思路&#xff0c;希望大家多指教 一、题目描述 又到了一年的末尾&#xff0c;项目组让小明负责为使得参加晚…

信创项目推进步骤

信创项目推进步骤 文章目录 信创项目推进步骤1. 制定信创替代计划2. 选择合适的信创产品3. 进行试点验证4. 全面部署和替换5. 加强网络安全建设6. 培训和技术支持7. 持续监督和评估 1. 制定信创替代计划 需要对现有的信息化硬件设备进行全面的梳理和评估&#xff0c;确定哪些设…