多态的使用和原理(c++详解)

一、多态的概念

        多态顾名思义就是多种形态,它分为编译时的多态(静态多态)运行时的多态(动态多态),编译时多态(静态多态)就是函数重载,模板等,通过不同的参数来完成对不同的函数的调用(即生成多种形态)并且这个过程在编译阶段就已经完成

        动态多态是在运行时根据对象的实际类型来确定调用函数的哪个版本,完成不同的⾏为。

二、多态构成条件

1.虚函数

        在类成员函数的返回类型前面添加virtual关键字即为虚函数,注意:虚函数只能定义于普通成员函数,构造函数以及类外函数不能定义虚函数。

2.虚函数的重写

        虚函数重写指的是子类(派生类)对父类(基类)的重写。重写的要求是子类虚函数的返回值,函数名,参数类型必须和父类一模一样。但函数的实现逻辑不用相同。

        这里如果虚函数的重写没有加virtual,但是父类加了virtual那么子类依旧保持virtual的性质,也可构成重写。

        注意:对虚函数重写并没有要求缺省参数要相同,但在这里强烈建议把缺省参数设为相同值,要不然会给你带来很大的弊端和误导性。接下来我会讲到。

3.调用方式

        要实现多态效果,第⼀必须是基类的指针或引⽤,因为只有基类的指针或引⽤才能既指向派⽣类对象又能指向基类;第⼆派⽣类必须对基类的虚函数重写/覆盖,重写或者覆盖了,派⽣类才能有不同的函数,多态的不同形态效果才能达到。

⽐如火车买票这个操作,当普通⼈买票时,是全价买票;学⽣买票时,是优惠买票;军⼈买票时是优先买票,我们就可以用多态来实现,如下:

#include<iostream>
using namespace std;
class ticket
{
public:virtual void func(){cout << "普通票" << endl;}
private:
};
class student:public ticket
{
public:virtual void func(){cout << "学生票" << endl;}
private:
};
void fm(ticket& pu)
{pu.func();
}
int main()
{ticket tk;student stu;fm(tk);fm(stu);return 0;
}

4.override和final的修饰

        override关键字:因为多态的实现细节要求太多了特别是对虚函数的重写,因此C++11提供了override,可以帮助⽤⼾来检查虚函数的重写是否正确,需要放在重写的函数参数列表后面。

        final关键字:如果不想子类对该虚函数进行重写的话就可以使用final关键字,放在函数名后面。

5.协变 

        刚才我们说了虚函数的重写一定要满足子类虚函数的返回值,函数名,参数类型必须和父类相同。协变是个例外情况。当子类重写父类虚函数时,若与父类虚函数返回值类型不同,即父类虚函数返回父类对象的指针或引用,子类虚函数返回子类对象的指针或引用,此时称为协变。协变的实际意义并不⼤,所以我们了解⼀下即可。

代码示例:

class A{};
class B :public A{};
class ticket
{
public:virtual ticket* func()//ticket也可以是A{cout << "普通票" << endl;return this;}
private:
};
class student:public ticket
{
public:virtual student* func() override//student也可以是B{cout << "学生票" << endl;return this;}
private:
};

析构函数的重写

        父类的析构函数为虚函数,此时派⽣类析构函数只要定义,⽆论是否加virtual关键字,都与基类的析构函数构成重写,虽然基类与派⽣类析构函数名字不同看起来不符合重写的规则,实际上编译器对析构函数的名称做了特殊处理,编译后析构函数的名称统⼀处理成destructor所以基类的析构函数加了vialtual修饰,派⽣类的析构函数就构成重写

A* p1 = new A;
A* p2 = new B;
delete p1;
delete p2;

        假设B是A的子类上⾯的代码如果~A(),不加virtual,那么delete p2时只调⽤A的析构函数,没有调⽤B的析构函数,就会导致内存泄漏问题。

三、纯虚函数和抽象类

        在虚函数的参数列表后⾯写上=0,则这个函数为纯虚函数,纯虚函数不需要定义实现(实现没啥意义因为要被子类重写,但是语法上可以实现),只要声明即可。包含纯虚函数的类叫做抽象类,抽象类不能实例化出对象如果子类继承后不重写纯虚函数,那么子类也是抽象类。纯虚函数某种程度上强制了子类重写虚函数,因为不重写实例化不出对象。

四、多态原理

        在分析对象的储存空间时,我们讲过对于同一个类实例化出的不同对象,这些对象使用的函数都是相同的,不同的是它们成员变量。所以每个对象只需要对成员变量进行储存,不用对成员函数进行储存,每一个对象使用的都是这个类的公共成员函数。

        c++为虚函数单独设立了一块区域来储存虚函数的地址,叫做虚表,而这块区域其实 就是一个函数指针数组。即用来储存函数指针的一个数组。那么父类和子类就各自有一个虚表,在对象实例化的时候就会隐含(隐含:类似于成员函数里面看不见的this指针一样)着一个指针——虚表指针,来指向虚表。

#include<iostream>
using namespace std;
class A
{
public:virtual void func(){}
};
class B
{
public:void func(){}
};
int main()
{A a;B b;cout << "a:" << sizeof(a) << endl;cout << "b:" << sizeof(b) << endl;return 0;
}

而虚表指针也是需要占用空间的大家可以自行地去运行一下以上代码,输出结果为:

a:4(或8,即32位与64位机器的区别)

b:1

        所以在调用对象的虚函数时就跟以什么类型的形式调用无关,而是跟这个对象实例化时具体类型有关。

#include<iostream>
using namespace std;
class ticket
{
public:virtual void func(){cout << "普通票" << endl;}
};
class student :public ticket
{
public:virtual void func() {cout << "学生票" << endl;}
};
int main()
{ticket* tk = new student;tk->func();return 0;
}

以上的输出结果是“学生票”。

注意:根据切片原理,子类可强制类型转化为父类,父类不能强制类型转化为子类。

五、练习

以下程序输出结果是什么()

  • A:A->0
  • B:B->1
  • C:A->1
  • D:B->0
  • E:编译出错
  • F:以上都不正确

        这里虽然B类的func成员没有写virtual关键字,但它是由A继承下来的依旧保留virtual的性质,然后因为重写并为要求参数的缺省值相同,所以这里构成函数的重写。再来看主函数main,p调用了test,而test是A的成员函数隐含了一个const   A* (this指针)的参数类型,p传到test函数满足多态,所以这里调用的是B的func。但是这里有个坑,该题的输出结果并不是“B->0”,而是“B->1”。

        要注意重写只是重写了函数的实现,也就是说实现多态的时候相当于调用的是父类的接口声明和子类的函数实现,而并不关心子类的函数接口声明。

        所以在我们自己写虚函数的时候,最好把缺省参数设为相同值,要不然会给你带来很大的误导性。

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

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

相关文章

《论软件系统架构风格》写作框架,软考高级系统架构设计师

论文真题 系统架构风格&#xff08;System Architecture Style&#xff09;是描述某一特定应用领域中系统组织方式的惯用模式。架构风格定义了一个词汇表和一组约束&#xff0c;词汇表中包含一些构件和连接件类型&#xff0c;而这组约束指出系统是如何将这些构件和连接件组合起…

深度学习训练中的三种网络:监督、半监督和无监督的联系与区别

深度学习训练中&#xff0c;根据训练数据是否有标签&#xff0c;可以将网络分为三大类&#xff1a;监督学习、半监督学习和无监督学习。 目录 一、监督学习网络1.1 特点1.2 典型任务1.3 举例 二、半监督学习网络2.1 特点2.2 典型任务2.3 举例 三、无监督学习网络3.1 特点3.2 典…

两倍多的程序员,不等于两倍多的代码

两倍多的工程师&#xff0c;并不会交付两倍多的代码。为什么很多老板就是想不明白这道理呢&#xff1f;今天这篇文章&#xff0c;咱们就讨论下这事情。 有时候&#xff0c;两件不相关的事情通过一件事情联系起来后&#xff0c;会让我们产生一些非理性想法&#xff0c;甚至相信…

Python自动化-操作Excel

在数据处理和报表生成过程中&#xff0c;Excel是一个经常使用的工具。Python中的openpyxl库可以让您通过编程方式读取、写入和操作Excel文件&#xff0c;从而实现自动化的数据处理和报表生成。本文将介绍openpyxl库的基本用法和常见操作&#xff0c;帮助您快速上手使用Python处…

【android10】【binder】【3.向servicemanager注册服务】

系列文章目录 可跳转到下面链接查看下表所有内容https://blog.csdn.net/handsomethefirst/article/details/138226266?spm1001.2014.3001.5501文章浏览阅读2次。系列文章大全https://blog.csdn.net/handsomethefirst/article/details/138226266?spm1001.2014.3001.5501 目录 …

依赖不对应导致java文件不能正常显示

项目中若出现非正常显示的java文件&#xff0c;检查下是否依赖版本不对应。&#xff08;前提必须是maven项目&#xff09;

基于单片机的太阳能热水器控制系统的研究-设计说明书

设计摘要&#xff1a; 本研究旨在设计和实现基于单片机的太阳能热水器控制系统。太阳能热水器是一种有效利用太阳能来加热水的设备&#xff0c;在节能和环保方面具有显著的优势。本研究通过使用单片机技术&#xff0c;将传统的太阳能热水器与智能控制相结合&#xff0c;提高了…

底盘四轮转向运动学解析(含代码)

目录 写在前面的话四轮转向运动学解析四轮转向理论图解robot_control.py 完整代码关键参数完整代码 公式解析&#xff08;根据代码&#xff09;反相--模式1详细图解 正相--模式2轴心--模式3 写在前面的话 网上找了很多资料&#xff0c;对于四轮转向运动学描述的很少&#xff0…

如何快速免费搭建自己的Docker私有镜像源来解决Docker无法拉取镜像的问题(搭建私有镜像源解决群晖Docker获取注册表失败的问题)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 Docker无法拉取镜像 📒📒 解决方案 📒🔖 方法一:免费快速搭建自己的Docker镜像源🎈 部署🎈 使用🔖 备用方案⚓️ 相关链接 🚓️📖 介绍 📖 在当前的网络环境下,Docker镜像的拉取问题屡见不鲜(各类Nas查询…

意得辑(Editage)润色全网最低折扣

意得辑(Editage)润色全网最低折扣 优惠代码如图 可以点击我想要咨询&#xff5e; 意得辑论文润色服务优惠代码&#xff5c;提高论文投稿成功率的最佳选择 推荐理由&#xff1a; 意得辑是全球领先的学术论文润色服务平台&#xff0c;特别适合非母语作者。凭借其专业的编辑团队…

买软件服务白送软件产品还送同等价值的白酒或其它商品,我这不是亏到姥姥家了吗?

原创 超云艾艾 AI智造AI编程 2024年09月23日 21:15 北京 在“企业数字化转型、建设和升级面临的主要难题和解决之道”文中&#xff0c;我提到过&#xff0c;针对企业做数字化转型和升级可能遇到的人才、资金和技术问题&#xff0c;我们可以基于SCSAI平台提供的十大功能以及多年…

巴黎嫩事件对数据信息安全的影响及必要措施

2024年9月17日&#xff0c;黎巴嫩首都贝鲁特发生了多起小型无线电通信设备爆炸事件&#xff0c;导致伊朗驻黎巴嫩大使受轻伤。这一事件不仅引发了对安全的广泛关注&#xff0c;也对数据信息安全提出了新的挑战。 王工 18913263502 对数据信息安全的影响&#xff1a; 数据泄露风…

颍川陈氏——平民崛起的典范

园子说颍川 广州有一处老建筑“陈家祠”&#xff0c;豪华精美堪比皇宫&#xff0c;誉为“岭南建筑艺术明珠”、“新世纪羊城八景”之一&#xff0c;是全国文保单位&#xff0c;4A 级景区。主体建筑以中轴线三座厅堂为中心&#xff0c;由大小十九座单体建筑组成&#xff0c;占地…

SpringBoot教程(三十) | SpringBoot集成Shiro权限框架

SpringBoot教程&#xff08;三十&#xff09; | SpringBoot集成Shiro权限框架 一、 什么是Shiro二、Shiro 组件核心组件其他组件 三、流程说明shiro的运行流程 四、SpringBoot 集成 Shiro &#xff08;shiro-spring-boot-web-starter方式&#xff09;1. 添加 Shiro 相关 maven2…

基于SpringBoot+Vue+MySQL的电影院购票管理系统

系统展示 用户前台界面 管理员后台界面 系统背景 随着电影产业的蓬勃发展&#xff0c;电影院已成为人们休闲娱乐的重要场所。然而&#xff0c;传统的电影院购票管理系统存在诸多不便&#xff0c;如购票流程繁琐、排队时间长、无法提前选座等问题&#xff0c;给观众的观影体验带…

计算机毕业设计之:微信小程序的校园闲置物品交易平台(源码+文档+讲解)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

计算机毕业设计 校园新闻管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

隐匿发案:David律所代理艺术家Ina Tomecek的两张青蛙版权画维权

案件基本情况&#xff1a;起诉时间&#xff1a;2024-8-14案件号&#xff1a;2024-cv-07196原告&#xff1a;Ina Tomecek原告律所&#xff1a;Law Office of David Gulbransen起诉地&#xff1a;伊利诺伊州北部法院涉案商标/版权&#xff1a;原告品牌简介&#xff1a;Ina Tomece…

Qanything 2 0源码解析系列4 图片解析逻辑

Qanything 2.0源码解析系列4: 图片解析逻辑 文章转载自&#xff1a;https://www.feifeixu.top/article/8bb8401b-9689-453f-ab86-e3ecae414e12 &#x1f600; 前言&#xff1a; 这篇文章介绍Qanything针对图片类型文件的处理逻辑 qanything_kernel/core/retriever/general_doc…

FreeMarker 禁止自动转义标签-noautoesc

&#x1f496;简介 FreeMarker 是一个用 Java 语言编写的模板引擎&#xff0c;它被设计用来生成文本输出&#xff08;HTML 网页、电子邮件、配置文件等&#xff09;。在 FreeMarker 中&#xff0c;默认情况下&#xff0c;当你在模板中输出变量时&#xff0c;如果这些变量包含 …