C++ 多态性

在这里插入图片描述

一 多态性的分类

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

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.mzph.cn/diannao/12297.shtml

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

相关文章

【C++】详解C++的模板

目录 概念 ​编辑 语法 函数模板 类模板 非类型模板参数 模板的特化 函数模板特化 类模板特化 全特化 偏特化 分离编译 概念 模板是C中非常厉害的设计,模板把通用的逻辑剥离出来,让不同的数据类型可以复用同一种模板的逻辑,甚至可以…

Flutter 中的 DataTable 小部件:全面指南

Flutter 中的 DataTable 小部件:全面指南 在Flutter的Material组件库中,DataTable是一个用于展示数据的表格组件,它允许开发者以一种结构化和可滚动的方式展示数据集。DataTable非常适合展示详细信息,如表格数据、统计数据或配置…

PHP黑魔法之md5绕过

php本身是一种弱语言,这个特性决定了它的两个特点: 输入的参数都是当作字符串处理变量类型不需要声明,大部分时候都是通过函数进行类型转化php中的判断有两种: 松散比较:只需要值相同即可,类型不必相同,不通类型比较会先转化为同类型,比如全数字字符串和数字比较,会比…

凸优化理论学习三|凸优化问题(一)

系列文章目录 凸优化理论学习一|最优化及凸集的基本概念 凸优化理论学习二|凸函数及其相关概念 文章目录 系列文章目录一、优化问题(一)标准形式的优化问题(二)可行点和最优点(三)局部最优点(四…

《Python编程从入门到实践》day28

# 昨日知识点回顾 安装Matplotlib 绘制简单的折线图 # 今日知识点学习 15.2.1 修改标签文字和线条粗细 # module backend_interagg has no attribute FigureCanvas. Did you mean: FigureCanvasAgg? # 解决办法:matplotlib切换图形界面显示终端TkAgg。 #…

使用Three.js绘制快速而逼真的水

本文将利用GPUComputationRenderer来实现水波纹的绘制,相似的案例可以看threejs官方的GPGPU Water示例。更多精彩内容尽在数字孪生平台。 什么是 GPGPU GPGPU代表通用图形处理单元(General-Purpose Graphic Processing Unit),意思…

1146 -Table ‘performance schema.session variables‘ doesn‘t exist的错误解决

一、问题出现 今天在本地连数据库的时候,发现这个问题,哎呦我擦,差点吓死了 二、解决办法 1)找文件 用everything搜一下MySQL Server 5.7 然后去Windows服务找一下MySQL配置文件的具体路径 如果知道那最好,不知道那…

宝塔8.1.0去除绑定用户

非要绑定手机号,确实很烦 1,/www/server/panel/BTPanel __init__.py if not public.is_bind():return redirect(/bind, 302) 将is_bind的路由全部注释 2,/www/server/panel/class下 panelPlugin.py 注释异常, 新增 softLis…

SSL协议

SSL 安全传输协议(安全套接层) 也叫TLS ---- 传输层安全协议 SSL的工作原理:SSL协议因为是基于TCP协议工作的,通信双方需要先建立TCP会话。因为SSL协议需要进行安全保证,需要协商安全参数,所以也需要建立…

【MySQL】7.MySQL性能优化的六大核心策略

数据库的性能对整个应用的响应速度和用户体验起着至关重要的作用。MySQL,作为广泛使用的开源关系型数据库,提供了丰富的性能优化手段。从资源优化、查询优化到结构、配置、代码乃至架构优化,每一个层面的调整都可能带来性能的飞跃。本文将深入…

springboot房屋租赁系统

摘要 房屋租赁系统;为用户提供了一个房屋租赁系统平台,方便管理员查看及维护,并且可以通过需求进行设备信息内容的编辑及维护等;对于用户而言,可以随时进行查看房屋信息和合同信息,并且可以进行报修、评价…

清理缓存简单功能实现

在程序开发中,经常会用到缓存,最常用的后端缓存技术有Redis、MongoDB、Memcache等。 而有时候我们希望能够手动清理缓存,点一下按钮就把当前Redis的缓存和前端缓存都清空。 功能非常简单,创建一个控制器类CacheController&#xf…

SpringBoot PowerMockito 私有/静态/方法/属性

SpringBoot PowerMockito 私有/静态/方法/属性 1 PrepareForTest2 待测试类3 测试类 1 PrepareForTest PrepareForTest 是 PowerMockito 提供的一个注解,用于告诉 PowerMockito 哪些类需要被修改以允许使用 PowerMockito 的功能。 PowerMockito 主要用于修改 Java…

【计算机毕业设计】基于SSM+Vue的线上旅行信息管理系统【源码+lw+部署文档+讲解】

目录 1 绪论 1.1 研究背景 1.2 设计原则 1.3 论文组织结构 2 系统关键技术 2.1JSP技术 2.2 JAVA技术 2.3 B/S结构 2.4 MYSQL数据库 3 系统分析 3.1 可行性分析 3.1.1 技术可行性 3.1.2 操作可行性 3.1.3 经济可行性 3.1.4 法律可行性 3.2系统功能分析 3.2.1管理员功能分析 3.2.…

JavaScript精粹(一)

JavaScript(简称为JS)是一种广泛应用于网页开发的脚本语言,具有以下几个主要作用: 网页交互:JavaScript 可以用于创建动态的网页效果,例如响应用户的操作,实现页面内容的动态更新,以…

Java SE vs Java EE:深入剖析及面试指南

Java 平台提供了多个版本来满足不同应用场景的需求,其中最常用的是 Java SE(Standard Edition)和 Java EE(Enterprise Edition)。理解这两个版本的区别对于任何 Java 开发者都是至关重要的,尤其是在面试过程…

C++字符串细节,面试题06

文章目录 22. 字符串22.1. 字符数组 vs 字符指针 vs 常量字符指针 vs string22.2. strcpy vs sprintf vs memcpy22.3. strlen vs length vs size vs sizeof22.4. 字符串之间的转换22.5 其他数据类型与字符串之间的转换22.6 字符串分割 22. 字符串 22.1. 字符数组 vs 字符指针 …

Spring整合其他技术

文章目录 Spring整合mybatis思路分析Mybatis程序核心对象分析整合Mybatis 代码实现 Spring整合Junit修改成警告 Spring整合mybatis 思路分析 Mybatis程序核心对象分析 上面图片是mybatis的代码,上述有三个对象,分别是sqlSessionFactory,sqlS…

Linux:配置客户端自定义autofs服务

Linux:配置客户端自定义autofs服务 修改autofs的主策略文件 [rootserver200 data]# vim /etc/auto.master# 修改内容如下 /misc /etc/auto.misc # 挂载目录的上级目录 /mnt /etc/auto.timinglee --timeout3修改autofs的自定义策略文件 [rootserver200 data]…

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

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