| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> C++知识库 -> C++多态 -> 正文阅读 |
|
[C++知识库]C++多态 |
📋 个人简介
前言之前我们已经将面向对象三大特性中的封装和继承讲了,接下来剩下最后一个环节了,那就是 多态。 多态概念通俗来说,就是去做相同一件事时,不同的人有不同的状态。比如买火车票,普通人是一个价格,而但学生去买就有一定的折扣,这就是一种多态。 多态定义多态是在不同继承关系的类对象,去调用同一函数,产生不同的行为。而要形成多态,必须满足下面这两个条件。
首先解释一下上面的一些名词,基类就是父类。 虚函数,我们在上篇文章讲虚拟继承时使用了一个关键字叫virtual,而虚函数就是用这个关键字修饰的函数,比如下面的 BuyTicket函数就是一个虚函数。
那么什么是虚函数的重写(覆盖)呢?
还是以买票为例子,我们创建两个类People和Student,二者都有BuyTicket这个行为,但二者两个函数的实现不同,此时我们可以称Student重写了Person类的BuyTicket函数。
此时,BuyTicket这个行为就构成了多态,当我们使用不同对象的父类引用去调用这些函数时,就会产生不同的行为。
此时我们可以看到,当我们传子类对象给Buy函数时调用的为子类中的函数,而父类传过去,调用的为父类函数。 虚函数重写两个例外我们之前提到在C++中构成函数重写的两个条件:
大部分情况下,都必须遵循这两个条件,但C++不愧是C艹,没有意外的话,它一定会出意外。
三个概念的辨析目前为止,我们已经学了重载,重写,重定义(隐藏),那么三者有什么区别呢? 抽象类在虚函数的后面写上 =0 ,则这个函数为纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口类),抽象类不能实例化出对象。派生类继承后也不能实例化出对象,只有重写纯虚函数,派生类才能实例化出对象。 再继续以买票为例子,首先我们将Person类定义为一个抽象类。
我们将Person类的BuyTicket函数设置为纯虚函数,此时Person类就是一个抽象类,我们无法使用Person类去实例化一个对象。只有当我们的类去重写这个虚函数之后,才能去实例化对象。
此时我们就可以用Student类去实例化一个对象。
多态实现原理接下来,我们就来看看底层,去揭开多态的神秘面纱,看看多态究竟是如何去实现的。 虚函数表概念首先我们先来看看下面这道题目,看看大家能否答对?
大家觉得这个程序应该输出什么呢? 我相信肯定会有人马上喊:答案是4,因为函数不存在类中,类中只存成员变量,这个类中只有b成员占4个字节,所以答案是4。好巧不巧,我一开始也以为是这个样子,并且觉得这个题这么简单有什么好考的。可当程序运行起来,我傻眼了。 答案是8,这是为什么? 接下来我们使用调试来看看,这个类中到底有什么东西,使它的大小变成了8字节。 我们可以发现,在tmp对象中还偷偷藏了一个指针,那么这个指针又是用来干什么的呢? 我们发现了一个熟悉的东西,这个不正是我们所写的虚函数的名字吗
存在原因现在我们知道了什么是虚函数指针,以及虚函数表的概念,那么为什么需要这个表和这个指针呢?我们接下来再往后看
我们分别写了两个类,一个A类作为父类,其中有三个不同的函数,一个B类作为子类,从A类继承而来。首先我们并不对B类进行任何操作,来看看A类和B类中成员的情况。 我们可以看到二者的虚函数指针指向同一片空间,存的虚函数表相同,我们还可以发现,虚函数表中并没有Func3,说明在虚函数表中存放的只有虚函数的地址。 接下来我们在B类中对Func1进行一个重写,来看看是否会发生什么变化。
此时我们发现b对象中的虚函数指针发生了变化,它不再与a对象的虚函数指针指向相同空间,同时b对象的虚函数表中的第一个函数也发生了变化,变为了它自己的成员函数。 根据目前的现象,我们可以得出一个结论:所谓重写实际上是对虚函数指针所指向的位置进行一个重写。 为了实现重写,我们需要这个指针和这个表的存在 动态链接和静态链接虚函数表和虚函数指针的事我们先告一段落,等会我们再来看它,接下来呢,我们来看看普通调用和多态调用,二者在汇编代码上有何区别。 我们把刚刚的A类和B类拿过来,再次使用。
我们来看看Func1()和Func3()二者汇编代码的区别。 我们可以很明显的发现多态调用一个函数,比普通调用一个函数多了很多的汇编代码,多出来的汇编代码其实就是一个查表的过程。多态调用其实就是查虚函数表,然后从虚函数中取出要调用的函数的地址,再去call。而普通函数的调用就是直接去call这个函数的地址。 这种在程序运行期间,根据具体拿到的类型确定程序的具体行为,调用具体的函数,称为动态链接。 既然有动态链接,当然也有静态链接**,静态链接是在程序编译期间就确定了程序的行为,调用具体的函数**。比如:函数重载。 总结有了上面的虚函数表和动态链接的知识后,我们再来补上多态原理的最后一环,来解释一下为什么多态需要使用父类的指针或引用才能实现。 大家记不记得我们在聊继承的时候,讲过一个切片。不记得的朋友可以移步去看看(56条消息) C++继承_。菀枯。的博客-CSDN博客 在进行切片时,我们也会将子类的虚函数指针给父类。因此函数的重写原理如下:
结语欢迎各位参考与指导!!! |
|
C++知识库 最新文章 |
【C++】友元、嵌套类、异常、RTTI、类型转换 |
通讯录的思路与实现(C语言) |
C++PrimerPlus 第七章 函数-C++的编程模块( |
Problem C: 算法9-9~9-12:平衡二叉树的基本 |
MSVC C++ UTF-8编程 |
C++进阶 多态原理 |
简单string类c++实现 |
我的年度总结 |
【C语言】以深厚地基筑伟岸高楼-基础篇(六 |
c语言常见错误合集 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/23 13:12:26- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |