当前位置: 首页 > news >正文

c++面向对象三大特性之一-----多态

前言:本文将介绍在32位平台下,c++的多态,通过本篇文章的学习你讲了解多态的原理,多态的底层还有一些不常见的关键字的介绍(final,override).

文章内容如下:        

        1:多态的概念

        2:多态的定义与实现

        3:多态的原理

        4:抽象类

        文章正式开始

1:多态的概念

       多态:不同对象去完成相同的行为时,产生不同的状态。

              我们可以用一个场景来增强对多态概念的理解:   12306铁路的买票

                比如说:成人与学生,买票的价格是不一样的,成人买票需要全价,学生买票只需半价,在这个经典的列子中,成人与学生他们都是去做相同的行为(买票),但是在买的时候却出现了不同的状态(价格不同)。

                在我们日常还有许许多多的例子比如:安卓手机买飞机票与苹果手机买飞机票的价格也不同,在比如说我们过年支付宝扫码,同样是扫码不同的人却获得了不同的红包大小。

        按照类型来分:多态可以分为:动态的多态与静态的多态

        静态多态:程序编译阶段就确定了函数的地址  :函数重载

        动态多态:在程序运行期间通过去对象中虚表中找到覆盖的函数的地址


2:多态的定义与实现

        前提:我们是在研究public继承过程中多态的条件。

        1:(父子类中)虚函数必须实现重写(函数名,返回值,参数类型这三个必须相同)

        2:父类对象的指针或者引用去调用实现重写的虚函数。

        


        在介绍多态之前我们先来了解几个概念:虚函数,虚函数的重写

        虚函数:在成员函数最前面+virtual关键字--->表示该成员函数是虚函数

        虚函数重写:父子类中三同(函数名\参数\返回值)

        下面我们通过代码再次加深对概念的理解。

        

class A
{
public:void fun1() { cout << "A::fun1() " << endl; }virtual void fun2() { cout << "A::virtual fun2()" << endl; }
private:int _a;
};
class B:public A
{
public:void fun1() { cout << "B::fun1() " << endl; }virtual void fun2() { cout << "B::virtual fun2()" << endl; }
private:int _b;
};

        在上面两个类中:  A类中:fun1为普通函数,fun2为虚函数

                                       B类中:  fun1也为普通函数,fun2为虚函数   所以根据概念我们可知:在A类和B类中fun1的关系为子类隐藏父类,fun2为重写的关系。知道了上述关系之后下面我们来实现多态调用的过程。

        未满足多态的条件。调用情况下

        

        多态调用的本质:如果是子类对象给父类对象的指针或引用,那么在多态调用的时候会去调用子类中重写的函数,如果是父类对象给父类对象的指针或者引用则调用父类中的函数,走的函数匹配原则。


        其实c++在确定多态调用的情况下还给了几种特殊的情况,如果满足则也构成多态的条件

        1:协变:虚函数的返回值可以不同,但是该返回值如果是父子类的指针或引用则也满足重写

               如下图展示:

        

        这个AB类与我们上面的类的关系一样B继承A,通过代码我们也可以知道尽管两个函数的返回值不一样,但是c++做了一个特殊处理,只要返回值为父子类指针或引用类型就可以构成多态。

        2:析构函数的重写

                父子类中析构函数会被做一个特殊的处理,在编译阶段编译器会将父子类中的析构函数函数名改为一样的,也就是说我们只需要在父子类析构函数前面加一个virtual虚函数关键字那么这两个函数也构成重写。

        如下图:

        

        在这个场景中我们可以看到,这个代码是有问题的因为,没有完成对子类对象的释放工作存在内存泄露,编译器经过编译阶段将父子类析构函数的函数名改为一样的,导致只调到了子类的析沟,所以在这种情况下我们需要完成对析构函数的重写,才能防止内存泄露。

        所以我们默认给父子类中都加上virtual关键字,实现对虚函数的重写。

                

        总结:析构函数的特殊处理,对于父子类析构函数建议加上virtual。

        3:只要父类中加了虚函数关键字virtual,子类可以不加,也构成重写但是一般建议加.

        c++的重写:是对内容进行重写,对于接口会被继承下来。

        


c++重载、重写(覆盖)、隐藏(重定义)概念的区分:

        

两个关键字的介绍:c++11  :final override

       final:1:final修饰一个类表明一个类不能被继承。(将一个类中的构造函数私有,这个类也不能被继承)。

               2:final修饰虚函数表明该虚函数不能被重写,如果函数被重写编译器会直接报错

     

  override关键字:能够检验一个派生类重写虚函数是否正确,不正确编译器直接报错。


3:多态的原理      

        在了解虚函数原理之前我们得先了解虚函数表指针/虚表指针.

        我们先来看一个普通的类(含有虚函数)他的大小会是多少?

        代码如下:

        

class A
{
public:virtual void fun1(){cout << "fun1" << endl;}
private:int _a;
};int main()
{cout << sizeof(A) << endl;return 0;
}

        这个类大小如果按照我们之前所学的知识我们可能认为它的值为4,但是并不是这样,因为对于类对象的存储有三种模型。

        1:将函数与变量都存在对象中.(显然这个模型不适合存储,太浪费空间了,调用的函数相同)

        2:将函数存在公共的区域,对象中只存储成员变量(适用于无虚函数的类)        

        3每个对象除了存储成员变量还会存储类函数表地址,函数表里为类成员函数的地址。(有虚函数的类).

        所以上面类A就为第三种存储模型,所以计算的大小为8(一个成员+一个指针).

        

        在cpp中我们将这个新加的指针_vfptr称为:虚函数表指针,他指向一个虚函数表(本质是一个函数指针数组)

        那么在单继承中多态的原理是什么呢?

        

class A
{
public:virtual void fun1(){cout << "A:fun1()" << endl;}virtual void fun2(){cout << "virtual void fun2()" << endl;}
private:int _a;
};
class B :public A
{
public:virtual void fun1(){cout << "B:fun1()" << endl;}
private:int _b;
};

        在这个场景中:B类继承A,会将A类中的虚函数表也给继承下来,只需要对完成重写的函数进行地址的覆盖就行,在继承过程中并不会增加新的虚函数表。如果B中还有其它虚函数则会在A中虚表中再加入一个地址。

        总结:虚函数表会被继承下来且不会增加再生成一个虚函数表,重写的虚函数会覆盖原父类中的虚函数,派生类的虚函数会被添加到基类中虚函数表中。

        将单继承可以看作下列的模型:子类=父类+自身变量

        


        那么在多继承中又是什么样子的呢?

        

class A
{
public:virtual void fun1(){cout << "A:fun1()" << endl;}virtual void fun2(){cout << "virtual void fun2()" << endl;}
private:int _a;
};class C
{
public:virtual void fun1(){cout << "virtual void fun1()" << endl;}
private:int _c;
};class D :public A, public C
{
public :virtual void Fund(){cout << " virtual Fund()" << endl;}
private:int _d;
};

        

        我们看到在多继承中:只要继承了几个父类就有几张虚表,并且如果派生类中还有虚函数,那么它会被添加到先继承类中的虚函数表中。多继承派生类的未重写的虚函数放在第一个继承基类部分的虚函数表中

        总结:多态的原理:通过基类对象的指针或者引用去引用派生类对象,那么在运行阶段,就会在虚函数表中找到覆盖的函数调用。


        补充知识:虚函数也是一个函数,最终形成可执行代码,所以虚函数是存在代码段的,而虚函数的地址被存放在虚函数表中的,而对象中存的是虚表指针,而在vs与g++下虚函数表也是存在代码段的(常量区).


        4:抽象类

        概念:含有纯虚函数的类叫做抽象类.

               纯虚函数:在虚函数后面+  =0的就叫做纯虚函数.

        如果一个类继承抽象类不做任何其它处理,那么这个类也叫抽象类。

                特点:抽象类不能实例化出对象,除非派生类中重写纯虚函数,规范了派生类的重写,另外纯虚函数也更加的体现出了接口继承.

        接口继承与实现继承

        普通函数的继承可以称为实现继承,而派生类虚函数的继承是接口继承是为了重写该虚函数,为了实现多态。

        本章知识点分享完毕。

相关文章:

c++面向对象三大特性之一-----多态

前言:本文将介绍在32位平台下,c的多态,通过本篇文章的学习你讲了解多态的原理,多态的底层还有一些不常见的关键字的介绍(final,override). 文章内容如下&#xff1a; 1:多态的概念 2:多态的定义与实现 3:多态的原理 4:抽象类 文章正式开始 1&#xff1a;多态的概念 多…...

8.Linux按键驱动-中断下半部

1.编程思路 1.1在gpio结构体中添加tasklet_struct结构体 1.2在probe函数中初始化tasklet结构体 1.3在中断服务程序中调度tasklet 1.4在这个函数中执行其它任务 2.代码&#xff1a; 应用程序和Makefile和上节一致 https://blog.csdn.net/weixin_40933496/article/details/1…...

Redis 线程控制 总结

前言 相关系列 《Redis & 目录》&#xff08;持续更新&#xff09;《Redis & 线程控制 & 源码》&#xff08;学习过程/多有漏误/仅作参考/不再更新&#xff09;《Redis & 线程控制 & 总结》&#xff08;学习总结/最新最准/持续更新&#xff09;《Redis &a…...

Scrapy框架原理与使用流程

一.Scrapy框架特点 框架&#xff08;Framework&#xff09;是一种软件设计方法&#xff0c;它提供了一套预先定义的组件和约定&#xff0c;帮助开发者快速构建应用程序。框架通常包括一组库、工具和约定&#xff0c;它们共同工作以简化开发过程。scrapy框架是python写的 为了爬…...

【C语言】字符型在计算机中的存储方式

ASCII对照表&#xff1a;https://www.jyshare.com/front-end/6318/ ASCII&#xff08;American Standard Code for Information Interchange&#xff0c;美国信息互换标准代码&#xff0c;ASCII&#xff09;是基于拉丁字母的一套电脑编码系统。它主要用于显示现代英语和其他西…...

python:ADB通过包名打开应用

一、依赖库 os 二、命令 1.这是查看设备中所有应用包名的最简单方法。只需在命令行中输入以下命令&#xff1a; adb shell pm list packages 2.打印启动的程序包名 adb shell am monitor回车&#xff0c;然后启动你想要获取包名的那个应用&#xff0c;即可获得 3.查看正在运…...

机器翻译技术:AI 如何跨越语言障碍

大家好&#xff0c;我是Shelly&#xff0c;一个专注于输出AI工具和科技前沿内容的AI应用教练&#xff0c;体验过300款以上的AI应用工具。关注科技及大模型领域对社会的影响10年。关注我一起驾驭AI工具&#xff0c;拥抱AI时代的到来。 AI工具集1&#xff1a;大厂AI工具【共23款…...

单调栈应用介绍

单调栈应用介绍 定义应用场景实现模板具体示例下一个最大元素I问题描述问题分析代码实现柱状图中最大的矩形问题描述问题分析代码实现接雨水问题描述问题分析代码实现最大宽度坡问题描述问题分析代码实现132模式问题描述问题分析代码实现定义 栈(Stack)是另一种操作受限的线性…...

部署前后端分离若依项目--CentOS7Docker版

一、准备 centos7虚拟机或服务器一台 若依前后端分离项目&#xff1a;可在下面拉取 RuoYi-Vue: &#x1f389; 基于SpringBoot&#xff0c;Spring Security&#xff0c;JWT&#xff0c;Vue & Element 的前后端分离权限管理系统&#xff0c;同时提供了 Vue3 的版本 二、环…...

PH47代码框架功能速查

1. PH47框架逻辑层全局引用对象 全局引用 功能简介 快速访问 bus 数据总线系统功能实现&#xff0c;如对总线数据项读写操作等 数据总线bus drv 驱动层功能实现&#xff0c;如飞控板相关的各种硬件传感器设备进行操作等 驱动层drv mcu 对mcu的片内接口及设备进行操作…...

UVM寄存器模型:uvm_reg_adapter

文章目录 一、什么是uvm_reg_adapter1、what2、Example2.1、代码详解 二、如何使用uvm_reg_adapter三、为什么要引入uvm_reg_adapter 一、什么是uvm_reg_adapter 1、what uvm_reg_adapter继承于uvm_object&#xff0c;定义了用于在 uvm_reg_bus_op 和特定总线事务之间进行转换…...

总结OpenGL和pyrender安装和使用过程中的坑

目录 报错一:AttributeError: NoneType object has no attribute glGetError 报错二:ImportError: (Unable to load OpenGL library, OSMesa: cannot open shared object file: No such file or directory, OSMesa, None) 报错三:raise ImportError("Unable to load…...

温湿传感器(学习笔记下)

接着我们温湿传感器上半部分的学习&#xff0c;现在我们学习接下来的部分&#xff0c;编写GXHTC3驱动程序&#xff0c;也就是给gxhtc3.c文件添加代码&#xff0c;我们要判断gxhtc3芯片是否存在和正常&#xff0c;就要先读取gxhtc3的ID号,根据gxhtc3的数据手册&#xff0c;读取命…...

期刊论文写作之word模板

一、zotero参考文献使用 下载zotero软件&#xff0c;请搜索相关帖子或者小破站即可&#xff1b; 把pdf拖到zotero软件里面&#xff0c;直接拉进去&#xff1b; 下面建立一个word演示&#xff1a; 1.导入pdf点击红框部分&#xff0c;根据期刊要求选择参考文献样式&#xff0…...

雷池社区版OPEN API使用教程

OPEN API使用教程 新版本接口支持API Token鉴权 接口文档官方没有提供&#xff0c;有需要可以自行爬取&#xff0c;爬了几个&#xff0c;其实也很方便 使用条件 需要使用默认的 admin 用户登录才可见此功能版本需要 > 6.6.0 使用方法 1.在系统管理创建API TOKEN 2.发…...

LSTM(Long Short-Term Memory,长短期记忆网络)在高端局效果如何

lstm 杂乱数据分析 LSTM&#xff08;Long Short-Term Memory&#xff0c;长短期记忆网络&#xff09;在高端局&#xff0c;即复杂的机器学习和深度学习应用中&#xff0c;展现出了其独特的优势和广泛的应用价值。以下是对LSTM在高端局中的详细解析&#xff1a; 一、LSTM的优势…...

模组操作宝典:4种关机重启技巧,让你的设备运行无忧

今天我说的是关于关机重启技巧。 给4G模组VBAT断电关机&#xff0c;模组关机前未能及时退出当前基站&#xff0c;会有什么影响呢&#xff1f; 基站会误以为设备还在线&#xff0c;下次开机仍会拿着上次驻网信息去连基站。基站一看&#xff0c;上次链接还在——认为你是非法设…...

利用API接口实现旺店通和金蝶系统的无缝数据对接

旺店通销售出库对接金蝶销售订单(线下)的技术实现 在企业日常运营中&#xff0c;数据的高效流转和准确对接是确保业务顺畅运行的关键。本文将聚焦于一个具体案例&#xff1a;如何通过轻易云数据集成平台&#xff0c;实现旺店通企业奇门的数据无缝对接到金蝶云星空系统。我们将…...

热题100(hash)

热题100&#xff08;Hash&#xff09; 三道题目 1.两数之和&#xff08;√&#xff09; 49.字母异位词分组&#xff08;题解&#xff09; 128.最长连续序列(题解) 思路 第1题简单hash映射&#xff0c;O(n) 第49题,关键点在于Hashmap的形式&#xff0c;‘HashMap<Stri…...

Ubuntu下Mysql修改默认存储路径

首先声明&#xff0c;亲身经验&#xff0c;自己实践&#xff0c;网上百度了好几个帖子&#xff0c;全是坑&#xff0c;都TMD的不行&#xff0c;修改各种配置文件&#xff0c;就是服务起不来&#xff0c;有以下几种配置文件需要修改 第一个文件/etc/mysql/my.cnf 这个文件是存…...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

SciencePlots——绘制论文中的图片

文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了&#xff1a;一行…...

MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例

一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

Day131 | 灵神 | 回溯算法 | 子集型 子集

Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 笔者写过很多次这道题了&#xff0c;不想写题解了&#xff0c;大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

YSYX学习记录(八)

C语言&#xff0c;练习0&#xff1a; 先创建一个文件夹&#xff0c;我用的是物理机&#xff1a; 安装build-essential 练习1&#xff1a; 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件&#xff0c;随机修改或删除一部分&#xff0c;之后…...

【项目实战】通过多模态+LangGraph实现PPT生成助手

PPT自动生成系统 基于LangGraph的PPT自动生成系统&#xff0c;可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析&#xff1a;自动解析Markdown文档结构PPT模板分析&#xff1a;分析PPT模板的布局和风格智能布局决策&#xff1a;匹配内容与合适的PPT布局自动…...

Keil 中设置 STM32 Flash 和 RAM 地址详解

文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级

在互联网的快速发展中&#xff0c;高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司&#xff0c;近期做出了一个重大技术决策&#xff1a;弃用长期使用的 Nginx&#xff0c;转而采用其内部开发…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文全面剖析RNN核心原理&#xff0c;深入讲解梯度消失/爆炸问题&#xff0c;并通过LSTM/GRU结构实现解决方案&#xff0c;提供时间序列预测和文本生成…...

LeetCode - 199. 二叉树的右视图

题目 199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 思路 右视图是指从树的右侧看&#xff0c;对于每一层&#xff0c;只能看到该层最右边的节点。实现思路是&#xff1a; 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...