多态(C++)

多态(C++)

本文如果有错误或者不足的地方,希望各位大佬多多指点。

【本文目录】

  • 1.多态的概念
  • 2.多态的定义及实现
  • 3.抽象类
  • 4.多态的原理
  • 5.单继承和多继承的虚函数表

在这里插入图片描述


1.多态的概念

多态的概念就是:多种形态

多态就是可以有多种的形态。不同的身份去实现同一件事情,会有不同状态。例如当你是学生时,去买火车票会有学生的专属优惠,但是当你是社会人士时,就不会有这样的优惠。就像电影变形金刚中的汽车可以用多种形态。
在这里插入图片描述

2.多态的定义及实现

2.1.虚函数

被关键字virtual所修饰的函数,称为虚函数

2.2.多态的构成条件🚩

  • 子类重写父类的虚函数
  • 父类的指针或引用来调用

2.3.重写

函数名、返回值、参数列表一致(协变除外)

注意:在子类中,不添加关键字virtual也构成重写,因为从基类继承下来的虚函数,也具有虚函数的属性。

2.4.多态的实现


class Person
{
public:virtual void BuyTickets() { cout << "票价--全价" << endl; }
};class Student :public Person
{
public://子类重写父类的虚函数virtual void BuyTickets() { cout << "票价--学生价" << endl; }
};//父类的引用 ,父类的指针也可以
void fun(Person& p)
{p.BuyTickets();
}int main()
{Person p;Student s;fun(p); // 不同的对象调用会有不同的状态fun(s);return 0;
}

3.抽象类

类中包含纯虚函数的类称为抽象类

3.1纯虚函数

纯虚函数就是在虚函数后面加上=0,内部有纯虚函数的类是无法实例化对象的。子类也会继承这个特性。子类只有重写这个纯虚函数才可以实例化对象。

class A
{
public:virtual void show() = 0; //纯虚函数
};class B : public A
{
public:virtual void show() {} //子类重写父类的纯虚函数
};int main()
{//A a; // err 无法实例化B b; //没有重写纯虚函数时,无法实例化对象return 0;
}

4.多态的原理

4.1虚函数表

下面这个类的是多少?

class Person
{
public:virtual void show() {};
protected:int _p;
};int main()
{Person p;cout<< sizeof(p) << endl; //这个对象多大?return 0;
}

答案:这个对象的大小在32位平台是8字节,在64位平台下是16字节。

看图

在这里插入图片描述

解析:其中__vfptr是一个指针,叫做虚函数表指针,一个含有虚函数的类至少存在一个虚函数表指针,该指针指向的是虚函数表,虚函数表简称虚表。虚表可以看做一个数组,内部存放的虚函数的地址,一般这个数组最后存放的是nullptr。

指针在32位平台下占4字节,在64位平台占8字节空间。因此在32位平台对象p的大小是8字节空间,而在64位平台大小是16字节,在64位下时需要内存对齐因此是16字节,不是12字节。

虚函数存在哪?虚表存在哪?

  • 代码段

class Person
{
public:virtual void BuyTickets() { cout << "票价--全价" << endl; }
};class Student :public Person
{
public://子类重写父类的虚函数virtual void BuyTickets() { cout << "票价--学生价" << endl; }
};void Print()
{int i = 0;//存放栈区int* pt = &i;int* pi = new int; //存放堆区const char* pc = "hello";printf("%p\n", pt);printf("%p\n", pi);printf("%p\n", pc);printf("%p\n",&(Person::BuyTickets));}int main()
{Print();return 0;
}

输出结果:
在这里插入图片描述

根据实例分析:分别打印栈区、堆区、代码段的变量地址得出,虚函数表和虚函数时存放在代码段的。

class Person
{
public:virtual void show1() {};virtual void show() {};
protected:int _p;
};
class Student:public Person
{public:virtual void show() {};virtual void show2() {};
protected:int _ps;};int main()
{Person p;Student s;return 0;
}

打开VS2022的监视窗口

在这里插入图片描述

看图解析:

  1. 基类和派生类都有一个虚函数指针(__vfptr)

  2. 派生类是由两部份组成,一部分继承基类的成员,一部分是自己的成员。

3.派生类从基类继承下来的show1函数,并没有重写时,会发现和基类的show1函数地址是一样的。派生类中的show函数重写父类的show函数,会发现地址不同的。可以知道当子类重写父类的虚函数时,会进行覆盖的父类的虚函数。

【总结】

  • 编译器会将基类的虚表拷贝一份给派生类,当派生类重写基类的虚函数时,会把基类虚函数覆盖

4.2多态的原理

进行上面的分析,可以知道子类的虚函数重写会覆盖父类的虚函数。下面进行分析多态的原理

class Person
{
public:virtual void BuyTickets() { cout << "票价--全价" << endl; }
};class Student :public Person
{
public://子类重写父类的虚函数virtual void BuyTickets() { cout << "票价--学生价" << endl; }
};void fun(Person& p)
{p.BuyTickets();
}int main()
{Person p;fun(p);Student s;fun(s);return 0;
}

在这里插入图片描述

解析:

  • 当fun函数的调用参数是Person类的对象时,p的指向就是Person类的虚函数
  • 当fun的函数调用参数是Student类的对象时,子类重写父类的虚函数,将其覆盖,此时p的指向是Student的虚函数

4.3动态绑定和静态绑定

【静态绑定】

静态绑定也称为前期绑定(早绑定),在编译期间确定程序的行为。例如函数重载

【动态绑定】

动态绑定也称为后期绑定(晚绑定),在程序运行期间,根据拿到的类型确定程序的行为,调用具体的函数。也叫做动态多态

5.单继承和多继承的虚函数表

【单继承】

class C1 
{
public:virtual void fun1() {}virtual void fun2() {}
};class C2:public C1
{
public:virtual void fun1() {}virtual void fun3() {}virtual void fun4() {}
};typedef void(*VFPTR) ();
void PrintVPTable(VFPTR p[])
{cout << "虚函数指针" << p << endl;for (int i = 0; p[i] != nullptr; i++){printf("第 %d 个函数地址:OX%x\n",i,p[i]);VFPTR f = p[i];f();}cout << endl;
}int main()
{C1 c1;VFPTR* VFPTR_c1 = (VFPTR*)(*(int*)&c1); PrintVPTable(VFPTR_c1);C2 c2;VFPTR* VFPTR_c2 = (VFPTR*)(*(int*)&c2);PrintVPTable(VFPTR_c2);return 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

当子类继承父类的成员时,子类内部具有父类同时也具有子类成员,当子类调用父类成员时,会进行切割行为。子类重写虚函数时,切割子类中的父类成员,覆盖父类的拷贝出来虚函数表。

【多继承】

class C1 
{
public:virtual void fun1() { cout << "C1::fun1" << endl; }virtual void fun2() { cout << "C1::fun2" << endl; }
};class C2
{
public:virtual void fun1() { cout << "C2::fun1" << endl; }virtual void fun2() { cout << "C2::fun2" << endl; }
};class C3:public C2,public C1
{
public:virtual void fun1() { cout << "C3::fun1" << endl; }virtual void fun3() { cout << "C3::fun3" << endl; }virtual void fun4() { cout << "C3::fun4" << endl; }
};typedef void(*VFPTR) ();
void PrintVPTable(VFPTR p[])
{cout << "虚函数指针" << p << endl;for (int i = 0; p[i] != nullptr; i++){printf("第 %d 个函数地址:OX%x -> ",i,p[i]);VFPTR f = p[i];f();}cout << endl;
}int main()
{C1 c1;VFPTR* VFPTR_c1 = (VFPTR*)(*(int*)&c1); PrintVPTable(VFPTR_c1);C2 c2;VFPTR* VFPTR_c2 = (VFPTR*)(*(int*)&c2);PrintVPTable(VFPTR_c2);C3 c3;VFPTR* VFPTR_c3 = (VFPTR*)(*(int*)&c3);PrintVPTable(VFPTR_c3);return 0;
}

在这里插入图片描述

看图得知:

  • 多继承的派生类未重写的虚函数会放第一个继承虚函数表中
  • 多继承的派生类重写虚函数时,会进行全部覆盖

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

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

相关文章

【Leetcode 160】环形链表——双指针,细节讲解

题目 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置&#…

RTSP/Onvif安防视频监控云平台EasyNVR重启后通道在线视频无法播放,接口报错502是什么原因?

EasyNVR安防视频云平台是旭帆科技TSINGSEE青犀旗下支持RTSP/Onvif协议接入的安防监控流媒体视频云平台。平台具备视频实时监控直播、云端录像、云存储、录像检索与回看、告警等视频能力&#xff0c;能对接入的视频流进行处理与多端分发&#xff0c;包括RTSP、RTMP、HTTP-FLV、W…

hypack如何采集多波束数据?(下)

多波束测量模块 1&#xff09;记录多波束和辅助传感器的数据&#xff1b; 2&#xff09;显示实时改正后的数据和数据质量信息。 ​编辑​ 测量准备 1&#xff09;设置大地测量参数和硬件设置&#xff1b; 2&#xff09;计划测线 计划测线是一定间距的平行线&#xff0c;…

微软联手清华,AI注释让文本到图像生成更符合人类偏好

获取本文论文原文PDF&#xff0c;请在公众号【AI论文解读】留言&#xff1a;论文解读 摘要 本研究展示了利用人类偏好数据集来精细调整文本到图像生成模型的潜力&#xff0c;增强了生成图像与文本提示之间的一致性。尽管取得了进展&#xff0c;现有的人类偏好数据集要么构建成…

掌控安全CTF-2024年5月擂台赛-WP(部分)

MISC ez_Misc 题目给了一个加密的压缩包和一个文本文档&#xff0c;首先我们先来看文本的内容&#xff0c;如下&#xff1a; 很容易看出&#xff0c;0宽隐写&#xff0c;用PuzzleSolver梭哈一下&#xff0c;发现了&#xff1a;Thi3 is n0t 2 hint 又在文本中发现一个特征&…

【2024】高校网络安全管理运维赛

比赛时间&#xff1a;2024-05-06 Re-easyre 基本的base64换表&#xff0c;用CyberChef解密 Re-babyre 进入主函数&#xff0c;发现输入四次 看一下就知道是大数求解 (当初写的时候差不多 不知道为什么第四个总是算错…) from z3 import *s Solver() # 设置一个解方程的类…

中心渗透Ⅱ

cs与msf权限传递以及mimikatz抓取win2012明文密码 使用Cobalt Strike抓取win2012明文密码&#xff0c;将会话传递到Metasploit Framework上 1.cs生成木马并使目标服务器中马 建立监听生成木马 2.抓取目标主机的明文密码 通过修改注册表来让Wdigest Auth保存明文口令 shell …

深入pandas:数据分析

目录 前言 第一点&#xff1a;导入模块 第二点&#xff1a;准备数据 第三点&#xff1a;简单的分析数据 第四点&#xff1a;【重点】数据透支 总结 前言 在数据分析与挖掘的领域&#xff0c;了解如何使用工具和方法来探索数据是至关重要的。本文将探讨如何利用Python中的…

C语言常用字符串处理函数

C语言中包含了很多对字符串处理的函数,要使用这些函数&#xff0c; 首先需要导入头文件#include <string.h> 1. strlen() -- 计算字符串长度 原型: size_t strlen(char const *string); 例: char *str "abcde"; size_t len strlen(str); // 结果为…

【DevOps】Elasticsearch在Ubuntu 20.04上的安装与配置:详细指南

目录 一、ES 简介 1、核心概念 2、工作原理 3、 优势 二、ES 在 Ubuntu 20.04 上的安装 1、安装 Java 2、下载 ES 安装包 3、创建 ES 用户 4 、解压安装包 5、 配置 ES 6、 启动 ES 7、验证安装 三、ES 常用命令 1、创建索引 2、 插入文档 3、查询文档 四、ES…

利用audacity和ffmpeg制作测试音频文件

最近要用SIPP测试一个场景&#xff0c;需要发送双声道/16K采样率/16bit量化的PCM流&#xff0c;但是下载的素材往往不能满足参数要求。那么就自己制作。 首先下载mp3文件&#xff0c;并用audacity打开。 接下来&#xff0c;点击菜单栏中轨道-重采样&#xff0c;将采样频率设为1…

【Java面试】四、MySQL篇(上)

文章目录 1、定位慢查询2、慢查询的原因分析3、索引3.1 数据结构选用&#xff1a;二叉树 & 红黑树3.2 数据结构选用&#xff1a;B树 4、聚簇索引、非聚簇索引、回表查询4.1 聚簇索引、非聚簇索引4.2 回表查询 5、覆盖索引、超大分页优化5.1 覆盖索引5.2 超大分页处理 6、索…

联发科MT8370平台Genio 510物联网应用程序处理器详细规格参数

MT8370是一款高度集成、功能强大的平台&#xff0c;专为各种人工智能(AI)和物联网(IoT)用例而设计&#xff0c;这些用例需要高性能边缘处理、先进的多媒体和连接功能、多个高分辨率摄像头、连接的触摸屏显示器以及多任务高级操作系统(HLOS)的使用。http://Genio 510 (MT8370) E…

Mybatis源码剖析

文章目录 一、前置1.1概念ORMSqlSession会话 二、快速入门2.1 SpringBoot整合Mybatis2.2 XML配置2.2.1 路径位置2.2.2 名称2.2.3 configuration标签内容环境environments标签映射器mappers标签 2.3 Mapper接口2.3.1 单Mybatis项目2.3.2 SpringBoot整合mybatis2.3.3 m整合mybati…

字符串函数(2)<C语言>

前言 快一周没更博客了&#xff0c;最近有点忙&#xff0c;今天闲下来了&#xff0c;还是不行&#xff0c;继续干&#xff0c;书接上回继续介绍字符串函数&#xff1a;strncpy()、strncat()、strcmp()、strtok()使用、strstr()使用以及模拟实现、strerror()使用。 strncpy()、s…

揭秘网络编程:同步与异步IO模型的实战演练

摘要 ​ 在网络编程领域&#xff0c;同步(Synchronous)、异步(Asynchronous)、阻塞(Blocking)与非阻塞(Non-blocking)IO模型是核心概念。尽管这些概念在多篇文章中被广泛讨论&#xff0c;它们的抽象性使得彻底理解并非易事。本文旨在通过具体的实验案例&#xff0c;将这些抽象…

在React中使用Sass实现Css样式管理-10

0. 什么是Sass Sass(Syntactically Awesome Stylesheets)是一个 CSS 预处理器&#xff0c;是 CSS 扩展语言&#xff0c;可以帮助我们减少 CSS 重复的代码&#xff0c;节省开发时间&#xff1a; Sass 引入合理的样式复用机制&#xff0c;可以节约很多时间来重复。支持变量和函…

C++之“流”-第2课-C++和C标准输入输出同步

为什么C和C的标准输入输出不同步时&#xff0c;数据会混乱&#xff1f;同步会带来多大性能损失&#xff1f;为什么说这个损失通常不用太在乎&#xff1f; 0. 课堂视频 C之“流”-第2课&#xff1a;和C输入输出的同步 1. 理解cin和cout的类型与创建过程 std::cout 是std::ostre…

添加、修改和删除字典元素

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 由于字典是可变序列&#xff0c;所以可以随时在字典中添加“键-值对”。向字典中添加元素的语法格式如下&#xff1a; dictionary[key] value 参数…

You don‘t have enough free space或者no space left on device异常

1.磁盘空间不足 Linux安装软件显示 You dont have enough free space 或者docker拉镜像时&#xff0c;出现磁盘空间不足的情况 no space left on device 如果你是ubuntu系统。查看磁盘空间 df -h 多半是这个目录满了/dev/mapper/ubuntu--vg-ubuntu--lv 大多情况我们只希望扩…