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). 文章内容如下: 1:多态的概念 2:多态的定义与实现 3:多态的原理 4:抽象类 文章正式开始 1:多态的概念 多…...
8.Linux按键驱动-中断下半部
1.编程思路 1.1在gpio结构体中添加tasklet_struct结构体 1.2在probe函数中初始化tasklet结构体 1.3在中断服务程序中调度tasklet 1.4在这个函数中执行其它任务 2.代码: 应用程序和Makefile和上节一致 https://blog.csdn.net/weixin_40933496/article/details/1…...
Redis 线程控制 总结
前言 相关系列 《Redis & 目录》(持续更新)《Redis & 线程控制 & 源码》(学习过程/多有漏误/仅作参考/不再更新)《Redis & 线程控制 & 总结》(学习总结/最新最准/持续更新)《Redis &a…...
Scrapy框架原理与使用流程
一.Scrapy框架特点 框架(Framework)是一种软件设计方法,它提供了一套预先定义的组件和约定,帮助开发者快速构建应用程序。框架通常包括一组库、工具和约定,它们共同工作以简化开发过程。scrapy框架是python写的 为了爬…...
【C语言】字符型在计算机中的存储方式
ASCII对照表:https://www.jyshare.com/front-end/6318/ ASCII(American Standard Code for Information Interchange,美国信息互换标准代码,ASCII)是基于拉丁字母的一套电脑编码系统。它主要用于显示现代英语和其他西…...
python:ADB通过包名打开应用
一、依赖库 os 二、命令 1.这是查看设备中所有应用包名的最简单方法。只需在命令行中输入以下命令: adb shell pm list packages 2.打印启动的程序包名 adb shell am monitor回车,然后启动你想要获取包名的那个应用,即可获得 3.查看正在运…...
机器翻译技术:AI 如何跨越语言障碍
大家好,我是Shelly,一个专注于输出AI工具和科技前沿内容的AI应用教练,体验过300款以上的AI应用工具。关注科技及大模型领域对社会的影响10年。关注我一起驾驭AI工具,拥抱AI时代的到来。 AI工具集1:大厂AI工具【共23款…...
单调栈应用介绍
单调栈应用介绍 定义应用场景实现模板具体示例下一个最大元素I问题描述问题分析代码实现柱状图中最大的矩形问题描述问题分析代码实现接雨水问题描述问题分析代码实现最大宽度坡问题描述问题分析代码实现132模式问题描述问题分析代码实现定义 栈(Stack)是另一种操作受限的线性…...
部署前后端分离若依项目--CentOS7Docker版
一、准备 centos7虚拟机或服务器一台 若依前后端分离项目:可在下面拉取 RuoYi-Vue: 🎉 基于SpringBoot,Spring Security,JWT,Vue & Element 的前后端分离权限管理系统,同时提供了 Vue3 的版本 二、环…...
PH47代码框架功能速查
1. PH47框架逻辑层全局引用对象 全局引用 功能简介 快速访问 bus 数据总线系统功能实现,如对总线数据项读写操作等 数据总线bus drv 驱动层功能实现,如飞控板相关的各种硬件传感器设备进行操作等 驱动层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,定义了用于在 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…...
温湿传感器(学习笔记下)
接着我们温湿传感器上半部分的学习,现在我们学习接下来的部分,编写GXHTC3驱动程序,也就是给gxhtc3.c文件添加代码,我们要判断gxhtc3芯片是否存在和正常,就要先读取gxhtc3的ID号,根据gxhtc3的数据手册,读取命…...
期刊论文写作之word模板
一、zotero参考文献使用 下载zotero软件,请搜索相关帖子或者小破站即可; 把pdf拖到zotero软件里面,直接拉进去; 下面建立一个word演示: 1.导入pdf点击红框部分,根据期刊要求选择参考文献样式࿰…...
雷池社区版OPEN API使用教程
OPEN API使用教程 新版本接口支持API Token鉴权 接口文档官方没有提供,有需要可以自行爬取,爬了几个,其实也很方便 使用条件 需要使用默认的 admin 用户登录才可见此功能版本需要 > 6.6.0 使用方法 1.在系统管理创建API TOKEN 2.发…...
LSTM(Long Short-Term Memory,长短期记忆网络)在高端局效果如何
lstm 杂乱数据分析 LSTM(Long Short-Term Memory,长短期记忆网络)在高端局,即复杂的机器学习和深度学习应用中,展现出了其独特的优势和广泛的应用价值。以下是对LSTM在高端局中的详细解析: 一、LSTM的优势…...
模组操作宝典:4种关机重启技巧,让你的设备运行无忧
今天我说的是关于关机重启技巧。 给4G模组VBAT断电关机,模组关机前未能及时退出当前基站,会有什么影响呢? 基站会误以为设备还在线,下次开机仍会拿着上次驻网信息去连基站。基站一看,上次链接还在——认为你是非法设…...
利用API接口实现旺店通和金蝶系统的无缝数据对接
旺店通销售出库对接金蝶销售订单(线下)的技术实现 在企业日常运营中,数据的高效流转和准确对接是确保业务顺畅运行的关键。本文将聚焦于一个具体案例:如何通过轻易云数据集成平台,实现旺店通企业奇门的数据无缝对接到金蝶云星空系统。我们将…...
热题100(hash)
热题100(Hash) 三道题目 1.两数之和(√) 49.字母异位词分组(题解) 128.最长连续序列(题解) 思路 第1题简单hash映射,O(n) 第49题,关键点在于Hashmap的形式,‘HashMap<Stri…...
Ubuntu下Mysql修改默认存储路径
首先声明,亲身经验,自己实践,网上百度了好几个帖子,全是坑,都TMD的不行,修改各种配置文件,就是服务起不来,有以下几种配置文件需要修改 第一个文件/etc/mysql/my.cnf 这个文件是存…...
接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...
2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...
【JVM】Java虚拟机(二)——垃圾回收
目录 一、如何判断对象可以回收 (一)引用计数法 (二)可达性分析算法 二、垃圾回收算法 (一)标记清除 (二)标记整理 (三)复制 (四ÿ…...
【LeetCode】算法详解#6 ---除自身以外数组的乘积
1.题目介绍 给定一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O…...
