多态及其原理

文章目录

    • 构成多态的条件
    • 虚函数
      • 作用:完成重写
    • 重写
    • 重载 重写 隐藏
    • 为什么析构函数要搞成符合多态?
    • 原理
      • 预热
      • 对于基类指针或引用指向父类或者子类的成员函数是如何调用不同的函数呢?

一个类如果是基类,它的析构函数最好加上virtual

构成多态的条件

  1. 必须通过基类的指针或者引用调用虚函数
  2. 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写

多态,不同对象传递过去,调用不同函数
多态调用看的指向的对象
普通对象(普通调用(不构成多态)),看当前者类型

虚函数

只有成员函数才可以加virtual
加上virtual它就叫做虚函数
在这里插入图片描述

作用:完成重写

重写

虚函数重写的一些细节:
// 重写的条件本来是虚函数+三同(即派生类虚函数与基类虚函数的
返回值类型、函数名字、参数列表完全相同),但是有一些例外
// 1、派生类的重写虚函数可以不加virtual – (建议大家都加上)
// 2、协变,返回的值可以不同,但是要求返回值必须是父子关系指针和引用

重载 重写 隐藏

函数重载发生在同一作用域

重写和隐藏 发生在基类和派生类
隐藏只要函数名一样就符合条件

为什么析构函数要搞成符合多态?

场景一

class Person
{
public:~Person(){cout << "~Person()" << endl;}
};
class Student:public Person
{
public:	~Student(){cout << "~Student()" << endl;}
};
int main()
{Person ps;Student st;return 0;	
}

这种情况下程序走的好着呢
在这里插入图片描述
也没上多态,不是也可以吗?为什么非得把父类和子类的析构函数搞成虚函数重写呢?
因为下面的场景下,不构成重写会造成内存泄漏

class Person
{
public:~Person(){cout << "~Person()" << endl;}
};
class Student:public Person
{
public:	~Student(){cout << "~Student()" << endl;delete[] _a;}
private:int* _a = new int[10];
};
int main()
{/*Person ps;Student st;*/Person* p = new Person;//基类指针既可以指向基类,也可以指向派生类delete p;p = new Student;  delete p;	//p->destructor() + operator delete(p)(free) 	//p是基类指针,指向Student,多态条件一满足//这里我们期望p指向谁,调用谁的析构//如果析构函数不构成多态,那么p->destructor() 是普通调用,只看当前者p的类型,永远只调用~personreturn 0;
}

运行结果
在这里插入图片描述
delete p 做了2件事

p->destructor() + operator delete§(free)

如果析构函数不构成多态,那么p->destructor() 是普通调用,只看当前者p的类型,永远只调用~person

这不是我们期望的,这里我们期望p指向谁,调用谁的析构

基类指针既可以指向基类,也可以指向派生类

那么我们就需要满足多态的条件
p是基类指针,指向Student,调用析构函数。多态条件一满足
编译器帮助我们把类析构函数都被处理成destructor这个统一的名字
形参类型一样,函数名一样,析构又没有返回值,那么就需加上virtual即可

class Person
{
public:virtual ~Person(){cout << "~Person()" << endl;}
};
class Student:public Person
{
public:	virtual ~Student(){cout << "~Student()" << endl;delete[] _a;}
private:int* _a = new int[10];
};
int main()
{/*Person ps;Student st;*/Person* p = new Person;//基类指针既可以指向基类,也可以指向派生类delete p;p = new Student;  delete p;	//p->destructor() + operator delete(p)(free) 	//p是基类指针,指向Student,多态条件一满足//这里我们期望p指向谁,调用谁的析构//如果析构函数不构成多态,那么p->destructor() 是普通调用,只看当前者p的类型,永远只调用~personreturn 0;
}

在这里插入图片描述

原理

预热

Base的大小是多少呢?
在这里插入图片描述
那么虚函数存在哪里呢?
存在了代码段(常量区)
回顾我们类和对象大小时的知识,成员函数也不保存在对象中,而是存放在公共的代码段
这里的vfptr是虚函数表指针,存的只是虚函数的地址!
成员函数加了virtual就会放到虚函数表指针里面

对于基类指针或引用指向父类或者子类的成员函数是如何调用不同的函数呢?

父类指针或者引用指向子类,发生切片,拿到的仍然是一个父类
指向父类还是父类
那么他们是如何调用不同的成员函数的呢?

class Person {
public:virtual void BuyTicket() { cout << "买票-全价" << endl; }int _a = 1;
};class Student : public Person {
public:virtual void BuyTicket() { cout << "买票-半价" << endl; }int _b = 1;
};void Func(Person& p)
{// 符合多态,运行时到指向对象的虚函数表中找调用函数的地址p.BuyTicket();
}int main()
{Person Mike;Func(Mike);Student Johnson;Func(Johnson);return 0;
}

Mike和Johnson的监视中看到他们的虚函数表里面存的地址不同,因为子类对父类的虚表进行了覆盖(子类拷贝了父类的虚表再进行重写)

P指针指向基类和指向子类时调用的函数是不同的地址
在这里插入图片描述
符合多态的话,P指向父类就是父类,P指向子类,完成切片后看到的还是一个子类,那么P到底是指向父类还是子类就不得而知了。
但是我不管,运行时,符合多态,运行时到指向对象的虚函数表中找调用函数的地址

在这里插入图片描述

在编译时就确定成员函数的地址
如果不符合多态,那么就看调用者P的类型,去Person里去找这个函数,在用函数名修饰规则就可以找到函数的地址
在这里插入图片描述在这里插入图片描述

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

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

相关文章

AlSD 系列智能安全配电装置是安科瑞电气有限公司专门为低压配电侧开发的一款智能安全用电产 品-安科瑞黄安南

一、应用背景 电力作为一种清洁能源&#xff0c;给人们带来了舒适、便捷的电气化生活。与此同时&#xff0c;由于使用不当&#xff0c;维护 不及时等原因引发的漏电触电和电气火灾事故&#xff0c;也给人们的生命和财产带来了巨大的威胁和损失。 为了防止低压配电系统发生漏…

2022 China Open Source Report

| 翻译&#xff1a;黄绍雅、岳扬、刘文涛、李思颖 | 编辑&#xff1a;胡欣元 | 设计&#xff1a;胡欣元 As 2022 finally came to an end, we also emerged from the challenging years of the three-year-long COVID pandemic. The new edition of the "China Open Sourc…

06.计算机网络——IP协议

文章目录 网络层IP协议基本概念协议头格式如何解包如何交付网段划分子网掩码特殊的IP地址IP地址的数量限制私有IP地址和公网IP地址路由 网络层 IP协议 IP协议提供一种将数据从A主机送达到B主机的能力&#xff0c;进行网络层的通信。 ​ IP协议 基本概念 主机 —— 配有IP地址…

MQ - 闲聊MQ一二事儿 (Kafka、RocketMQ 、Pulsar )

文章目录 MQ的发展史阶段一&#xff1a;追求解耦阶段二&#xff1a;追求吞吐量与一致性阶段三&#xff1a;追求平台化 MQ的通用架构主题topic、生产者producer、消费者consumer分区partition MQ 存储KafkaGood Design ---> 磁盘顺序写盘Poor Impact---> topic 数量不能过…

LabVIEW可重入VI,VI模板和动态VI之间的差异

LabVIEW可重入VI&#xff0c;VI模板和动态VI之间的差异 应该在何时使用可重入VI、模板VI和动态调用VI&#xff1f;这三种类型之间有什么区别&#xff1f; 可重入VI 当想要同时运行同一VI的多个实例时&#xff0c;将使用可重入VI。当VI不可重入时&#xff0c;VI只有一个数据空…

lama cleaner

这里写自定义目录标题 安装参数包含的额外plugins 安装 conda create --name lamacleaner python3.10 pip install -r requirements.txt pip install gfpgan pip install realesrgan pip install rembg pip install .如果安装本package报错&#xff0c;可以尝试改&#xff1…

后端(四):博客系统项目

咱们在这里实现的是后端项目&#xff0c;前端代码就提一提&#xff0c;不全做重点介绍&#xff0c;在开始讲解这个博客系统项目之前&#xff0c;我们先看看这个项目的前端界面&#xff1a; 登录界面&#xff1a; 个人主页&#xff1a; 博客详情页&#xff1a; 写博客页&#x…

常用API学习07(Java)

Date 在jdk1.8之前,java中的日期和时间是一类的&#xff0c;从1.8之后对日期和时间体系重新做了规划&#xff0c;划分出一个新的包 - java.time包&#xff0c;这个包中包含了日期、时间、时区、日历、单位。 Date&#xff0c;是java中最老的日期和时间类&#xff0c;后续退出…

Arcgis之 KML/KMZ文件转shp

一般我们在Goole Earth上勾画的区域导出后都为KML或者KMZ格式的&#xff0c;但无法在arcgis等软件上直接应用&#xff0c;故需进行一定的转换 1.打开ArcMap&#xff0c;选择ArcToolbox->Conversion Tools->From KML->KML To Layer 得到如下结果&#xff08;由于本KML…

pytest自动化测试框架tep环境变量、fixtures、用例三者之间的关系

tep是一款测试工具&#xff0c;在pytest测试框架基础上集成了第三方包&#xff0c;提供项目脚手架&#xff0c;帮助以写Python代码方式&#xff0c;快速实现自动化项目落地。 在tep项目中&#xff0c;自动化测试用例都是放到tests目录下的&#xff0c;每个.py文件相互独立&…

自动驾驶分级和技术架构

标题SAE 和 NHTSA自动驾驶分级 当前全球汽车行业中两个最权威的分级系统由美国国家公路交通安全管理局&#xff08;NHTSA&#xff09;和国际自动化工程师协会(SAE)提出。2013年&#xff0c;NHTSA将驾驶自动化的描述分为5个层级。2014年1月&#xff0c;SAE制定J3016自动驾驶分级…

Mybatis基础模块-日志管理

文章目录 1. 适配器模式2. Log2.1 默认实现StdOutImpl2.2 Log4jImpl 3. LogFactory4. 解析配置和应用4.1 settings配置4.2 解析 5. jdbc日志5. 1 类图5.2 BaseJdbcLogger5.3 ConnectionLogger5.4 ConnectionLogger的具体应用 1. 适配器模式 适配器使接口不兼容的对象可以相互合…

IDEA常用高效开发工具—screw一键生成数据库文档(仅需三步)

1.配置 引入screw核心... <!-- screw核心 --> <dependency><groupId>cn.smallbun.screw</groupId><artifactId>screw-core</artifactId><version>1.0.3</version> </dependency><!-- HikariCP --> <dependency…

VuePress在生产环境跳转子页报错 Failed to execute ‘appendChild‘ on ‘Node‘

记录一个使用VuePress时遇到的问题 使用VuePress做了一个文档网页&#xff0c;在开发环境的时候一切正常&#xff0c;但是发布到生产环境后&#xff0c;直接跳转二级页面会报错Failed to execute appendChild on Node 比如主页是http://sun/docs/.vuepress/dist/index.html#/…

【C语言项目】三子棋

文章目录 项目思路一、分文件进行创建二、进入游戏前的目录2.1 目录的功能&#xff1a;2.2 目录界面&#xff1a;2.3 选择进入或退出游戏2.4 多次重玩功能 三、画出棋盘3.1 写出棋子3.2 初始化棋盘3.2 画出棋盘的框架3.3 代码实现 四、玩家落子4.1 落子逻辑4.2具体情况分类讨论…

抖斗音直播间评论引流助手,支持直播间喊话+视频评论区喊话=到指定直播间引流精准粉丝【永久脚本+详细教程】

如果你觉得直播间发言手动太麻烦了&#xff0c;或许这个自动工具能帮到你&#xff01; 1.开始运行前&#xff0c;需要手动去打开打开直播间或者视频评论区&#xff0c;再运行脚本。 2.脚本就是模拟人工操作&#xff0c;在相应的APP里进行评论&#xff0c;无突破APP限制功能。…

【Kubernetes运维篇】ingress-nginx实现业务灰度发布详解

文章目录 一、理论&#xff1a;实现灰度发布的几种场景1、场景一&#xff1a;将新版本灰度给部分用户2、场景二&#xff1a;按照比例流程给新版本3、实现灰度发布字段解释 二、实践&#xff1a;1、实验前提环境2、基于Request Header(请求头)进行流量分割3、基于Cookie进行流量…

93.qt qml-自定义Table优化(新增:水平拖拽/缩放自适应/选择使能/自定义委托)

之前我们更新了90.qt qml-Table表格组件(支持表头表尾固定/自定义颜色/自定义操作按钮/排序)_qml 表格_诺谦的博客-CSDN博客 但是一直没出源码,是因为该demo还存在问题,那就是表头表尾固定下,如果是半透明状态下,会看到表头表尾固定后的内容,所以只能重构代码,不能使用重…

Vue3组合式API+TypeScript写法入门

文章目录 前言1.reactive2.ref3.props4.computed5.emit6.watch总结 前言 参考Vue3官网. 本篇以组合式API为例, 但不包含setup语法糖式写法. 原本打算结合class-component, Vue3不推荐就不用了: OverView|Vue Class Component. 而且是不再推荐基于类的组件写法, 推荐单文件组件…

Android App 持续集成性能测试:启动流量

目录 前言&#xff1a; get app UID 获取流量数据 获得启动流量数据 总结 前言&#xff1a; Jenkins 是一种开源的持续集成工具&#xff0c;可以帮助我们更加方便地进行软件开发和测试工作。通过 API 远程管理 Jenkins 可以帮助我们更加方便地进行 Jenkins 的配置和管理工…