C++从入门到入土(七)——多态

目录

前言

多态的概念

多态的定义

虚函数的介绍

虚函数的重写/覆盖

析构函数的重写

override和final关键字

纯虚函数和抽象类

重写/重载/隐藏总结

多态的原理

小结


前言

C++一共有三个特性,封装、继承和多态,在前面的文章中,我们分别介绍了封装和继承的概念,现在本篇文章将完成C++特性的最后一块拼图——多态。在实际生活中我们会看到这种情况,一个人有不同的身份,比如在学校的时候是老师,在家是孩子,工作了是老师;我们在买票时,成人全票,儿童半价;动物的叫声,狗是“汪汪”,猫是“喵喵”等这些都是多态的实例,多态通俗将就是一个事物的多种状态,那么有了这个认识,我们将开启多态的世界。

多态的概念

多态通俗讲就是多种状态,分为两种:编译时多态和运行时多态。我们在前面介绍的函数重载、类模板就是编译时多态,我们在这里不做过多介绍,我们今天主要介绍运行时的多态。

那么多态有什么作用呢?我们在编写代码时可能会出现下面的情况:基类当中有一个函数实现了一种功能,派生类在继承了基类后针对这个函数的功能要做出相应的调整,但函数结构大体不变,还是实现了这个功能,只不过实现方式不同,那么我们此时就可以使用多态定义这个新的函数,这样就可以保证基类代码不变的情况下,通过在派生类中的改变达到某种需求。这就是多态的核心作用

多态的定义

多态的实现需要两个条件:

1.必须是基类的指针或引用调用虚函数

2.被调用的必须是虚函数,并且完成了重写/覆盖

接下来我们将介绍虚函数和重写的概念。

虚函数的介绍

类成员函数名称前加上virtual就构成了虚函数,但是非成员函数不能用virtual修饰

虚函数的重写/覆盖

既然要保证基类代码不变的情况下,通过在派生类中添加相关功能达到某种需求,那么C++为我们提供的解决方案就是虚函数的重写/覆盖。

概念:派生类中有一个与基类完全相同的虚函数,称派生类重写了基类的虚函数
值得注意的是:派生类的虚函数如果不在前面加virtual也构成重写(但是在实际操作过程中建议在派生类中加上virtual)。重写是一种特殊的隐藏,即:不构成重写就是隐藏。

那么有了虚函数和重写后,我们可以参考下面代码,更加深入的理解多态的概念:

class Animal
{
public:virtual void sound(){cout << "啊啊" << endl;}
protected:string _name;int _weight;string _type;
};
class Dog :public Animal
{
public:virtual void sound(){cout << "汪汪" << endl;}
};void func(Animal&a)
{a.sound();
}

上述代码运行结果如下所示:

我们可以看到,通过传不同的类就调到了不同的函数,这就是多态要完成的任务。

那么虚函数的重写可以实现不同函数的调用,这是为什么呢?实际上重写就是组合,编译器将派生类重写的函数内容与基类虚函数的声明相互组合,从而实现函数的拼接调用

析构函数的重写

C++从入门到入土(六)——继承的介绍

我们在前面继承章节中介绍默认成员函数时,对析构函数是这么说的:派生类的析构函数会在对象生命周期结束后自动调用基类的析构函数清理基类成员,因为这样才能保证先清理基类再清理派生类的顺序。(析构先子后父)这是因为析构函数在编译时统一将名称改为destructor(),与多态有关这是为什么呢?

实际上基类的析构函数是虚函数,此时派生类析构函数只要定义,无论是否加virtual关键字,都与基类析构函数构成重写,虽然它们的名称看起来不符合重写规则,但实际上编译器做了特殊处理,将他们的名称统一处理成destructor(),这样就支持了函数重写,所以析构函数在定义时建议加上virtual。

override和final关键字

C++标准对于重写的定义是比较严格的,有时候我们会因为疏忽大意导致函数无法完成重写,因此C++为我们提供了override关键字,用来检测函数是否发生重写,其定义方式是:在派生类重写的虚函数后面加上override。

如果我们不想让这个函数发生重写,那么C++标准为我们提供了final关键字,其定义方式是:在基类不想发生重写的函数后面加上final。

override和final使用如下所示:

 

纯虚函数和抽象类

纯虚函数:在虚函数后面加上=0,则这个函数就是纯虚函数,纯虚函数不需要定义实现,因为不需要重写,只要声明即可。

抽象类:包含纯虚函数的类叫做抽象类,如果派生类继承之后不重写纯虚函数,那么派生类也是抽象类,纯虚函数在某种程度上强制派生类重写虚函数,因为不重写实例化不出对象。 

重写/重载/隐藏总结

重载:两个函数在同一作用域,函数名相同,参数不同,参数的类型或个数不同,返回值可以相同,可以不同

重写:两个函数分别在基类和派生类不同的两个作用域中,函数名,参数,返回值必须相同(协变除外),两个函数必须是虚函数

隐藏:两个函数或变量分别在基类和派生类两个不同的作用域,函数名相同,两个函数只要不是重写就是隐藏

多态的原理

在讲解多态之前,我们先来看一个问题:

class A
{
public:virtual void func(){cout << "func()" << endl;}
private:int _a;char _b;
};
int main()
{A a;int size = sizeof(a);cout << size << endl;return 0;
}

你们觉得上面代码的运行结果是什么(32位)?如果根据结构体对齐的概念,我们可以知道,这个结果应该是8,但事实真是如此吗?我们运行代码:

 结果与我们推测的有所差异,这是因为什么呢?我们进行调试:

我们可以看到a当中保存了三个变量,那么应该是这个_vfptr导致大小的改变,根据后面的ptr我们可以推测这个应该是指针,那么在32位机器下,指针大小应该是四字节所以其大小变为了12字节,那么这个_vfptr是什么东西呢?实际上这个_vfptr是一个虚函数指针数组,又叫虚函数表,所有的虚函数都是存储在这个虚表当中,我们在运行过程中就是通过虚表找到每个虚函数的地址,然后实现对应的函数调用。

小结

本篇文章我们完成了C++特性的最后一块拼图——多态,通过多态我们可以更加灵活的实现代码的编辑,为我们程序的书写提供了便利,受限于博主的知识水平,可能文章当中有所纰漏,欢迎大家指正,接下来我们继续更新C++从入门到入土系列,如果觉得我的文章对您有所帮助的话,希望您能够点赞、关注加收藏,您的支持是我创作的最大动力 

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

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

相关文章

浅谈时钟启动和Systemlnit函数

时钟是STM32的关键&#xff0c;是整个系统的心脏&#xff0c;时钟如何启动&#xff0c;时钟源如何选择&#xff0c;各个参数如何设置&#xff0c;我们从源码来简单分析一下时钟的启动函数Systemlnit&#xff08;&#xff09;。 Systemlnit函数简介 我们先来看一下源程序的注释…

【数据结构】6栈

0 章节 3&#xff0e;1到3&#xff0e;3小节。 认知与理解栈结构&#xff1b; 列举栈的操作特点。 理解并列举栈的应用案例。 重点 栈的特点与实现&#xff1b; 难点 栈的灵活实现与应用 作业或思考题 完成学习测试&#xff12;&#xff0c;&#xff1f; 内容达成以下标准(考核…

HOT100——链表篇Leetcode160. 相交链表

文章目录 题目&#xff1a;Leetcode160. 相交链表原题链接思路代码 题目&#xff1a;Leetcode160. 相交链表 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表…

江科大51单片机笔记【16】AD/DA转换(下)

写在前言 此为博主自学江科大51单片机&#xff08;B站&#xff09;的笔记&#xff0c;方便后续重温知识 在后面的章节中&#xff0c;为了防止篇幅过长和易于查找&#xff0c;我把一个小节分成两部分来发&#xff0c;上章节主要是关于本节课的硬件介绍、电路图、原理图等理论知识…

【CF】Day5——Codeforces Round 921 (Div. 2) BC

B. A Balanced Problemset? 题目&#xff1a; 思路&#xff1a; 这道题要我们分成n个子问题&#xff0c;我们假设这几个子问题分别是a1,a2,a3,...an&#xff0c; 那么就是让我们求 gcd(a1,a2,a3,....,an)&#xff0c;我们假设这个值是d 那么就有 d | a1&#xff0c;d | a2…

Mininet 自定义拓扑类型详解

Mininet 通过 --topo 参数支持多种自定义网络拓扑结构&#xff0c;适用于不同场景的网络模拟需求。以下是所有内置拓扑类型及其参数说明&#xff1a; 一、基础拓扑类型 拓扑类型参数格式说明示例命令singlesingle,<n>单一交换机连接所有主机&#xff08;默认 2 台主机&a…

图论part3|101.孤岛的总面积、沉没孤岛、417. 太平洋大西洋水流问题

101. 孤岛的总面积 &#x1f517;&#xff1a;101. 孤岛的总面积思路&#xff1a;和昨天的岛的区别是&#xff1a;是否有挨着边的岛屿 所以可以先遍历四条边挨着的岛屿&#xff0c;把他们标记为非孤岛再计算其他岛屿当中的最大面积 代码&#xff1a;&#xff08;深度搜索&…

第十一届蓝桥杯单片机国赛

什么&#xff1f;4T模拟赛和省赛做起来轻轻松松&#xff1f;不妨来挑战一下第十一届国赛&#xff0c;这一届的国赛居然没考超声波、串口通信&#xff01;只要你正确地理解了题目的意思&#xff0c;规避出题人挖的坑&#xff0c;拿个国一轻轻松松。 附件&#xff1a;第十一届蓝桥…

【Unity6打包Android】游戏启动的隐私政策弹窗(报错处理)

Unity版本&#xff1a;Unity6000.0.24 增加弹窗步骤 1. 自定义AndroidManifest 1.1 在Player Setting > Publishing Settings > Build下勾选Custom Main Manifest&#xff0c;在Assets/Plugins/Android路径下生成AndroidManifest.xml文件 1.2 修改AndroidManifest.xml…

记录一个SQL自动执行的html页面

在实际工作场景中&#xff0c;需要运用到大量SQL语句更新业务逻辑&#xff0c;对程序员本身&#xff0c;写好的sql语句执行没有多大问题&#xff08;图1&#xff09;&#xff0c;但是对于普通用户来说还是有操作难度的。因此我们需要构建一个HTML页面&#xff08;图2&#xff0…

mac安装mysql之后报错zsh: command not found: mysql !

在Mac上安装MySQL后&#xff0c;如果终端中找不到mysql命令&#xff0c;通常是 因为MySQL的命令行工具&#xff08;如mysql客户端&#xff09;没有被正确地添加到你的环境变量中。 检查 MySQL 是否已安装 ps -ef|grep mysql查看到路径在 /usr/local/mysql/bin 查看 .bash_pro…

socket编程与TCP协议

如果你想和远方的朋友通电话&#xff0c;但是&#xff0c;没有办法直接把自己的声音放在电线上变成电流信号&#xff0c;你需要使用电话机拿起听筒拨号&#xff0c;而这个电话就是Socket&#xff0c;它让你简单方便地完成电流通话&#xff0c;从我们编程的角度来看&#xff0c;…

css基本功

为什么 ::first-letter 是伪元素&#xff1f; ::first-letter 的作用是选择并样式化元素的第一个字母&#xff0c;它创建了一个虚拟的元素来包裹这个字母&#xff0c;因此属于伪元素。 grid布局 案例一 <!DOCTYPE html> <html lang"zh-CN"><head&…

环境配置 | 5分钟极简Git入门:从零上手版本控制

你是否刚接触Git&#xff1f;别担心&#xff01;这篇指南将用最简单的步骤带你掌握Git核心操作&#xff0c;快速开启版本控制之旅&#xff01;✨ 1.git在win10上的下载安装 1.1.下载git 打开官方网站 Git - Downloadshttps://git-scm.com/downloads ​ ​​ 1.2.git安装 …

软件工程概述、软件过程模型、逆向工程(高软45)

系列文章目录 软件工程概述、软件过程模型、逆向工程。 文章目录 系列文章目录前言一、软件工程概述二、能力成熟度模型1.能力成熟度模型CMM2.能力成熟度模型集成CMMI 三、软件过程模型1.瀑布模型SDLC2.原型化模型3.螺旋模型4.增量模型5.喷泉模型6.敏捷模型7.统一过程模型RUP 四…

接口自动化入门 —— Jmeter实现在接口工具中关联接口处理方案

1. JMeter 接口关联处理的核心概念 接口关联是指在多个接口请求之间共享数据&#xff0c;例如将一个接口的返回值作为另一个接口的输入参数。常见的场景包括&#xff1a; 使用登录接口返回的 Token 作为后续接口的认证信息。 将一个接口返回的 ID 作为另一个接口的请求参数。…

websocket学习手册及python实现简单的聊天室

概述 WebSocket 是一种网络通信协议&#xff0c;允许在单个 TCP 连接上进行全双工通信。它最核心的优势就在于实现了持久连接&#xff0c;实现了实时的数据传输。HTTP 协议有一个很大的缺点&#xff0c;通信只能由客户端发起&#xff0c;服务器返回响应后连接就会关闭&#xf…

小白学习:提示工程(什么是prompt)

课程链接 https://www.bilibili.com/video/BV1PX9iYQEry/?spm_id_from333.337.search-card.all.click 一 什么是提示工程 【提示工程】也叫【指令工程】 prompt就是给大模型发的指令&#xff0c;如“给我讲个笑话” 懂得提示工程原理会带来什么优势 懂得原理 为什么有的指…

ROS实践(五)机器人自动导航(robot_navigation)

目录 一、知识点 1. 定位 2. 路径规划 (1)全局路径规划 (2)局部路径规划 3. 避障 二、常用工具和传感器 三、相关功能包 1. move_base(决策规划) 2. amcl(定位) 3. costmap_2d(代价地图) 4. global_planner(全局规划器) 5. local_planner(局部规划器…

分治算法区

分治 一.分治二.经典应用案例三.快速排序&#xff08;1&#xff09;颜色分类&#xff08;2&#xff09;排序数组&#xff08;3&#xff09;数组中第K个最大的元素 四.归并排序1.排序数组2.交易逆序对总数3.计算右侧小于当前元素的个数4.翻转对 一.分治 分治算法是一种通过将复…