IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: 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++]面向对象语言三大特性--多态

大家这篇文章描述的是我在学习多态时的一些学习笔记,和问题,还有一些面试题,希望这篇文章对你会有帮助

在这里插入图片描述



什么是多态?

下定义之前先讲个例子:

加入你是一个铲屎官,且家里有三个祖宗 🐱 、🐶 、🐰,那么在要干饭的时候,你为他们准备的食物分别是 猫粮,狗粮,胡萝卜。那么这里为不同的宠物准备不一样的食物就可以看做多态


下定义:

在对待同一件事(喂食)的时候会有不同的结果(食物)

z

如何才可以看到多态这一属性呢?(概念)

多态是在继承后的基础上拓展出来的,那么需要看这一个特性必须要满足以下的条件

  1. 必须是父子类(等于白说)
  2. 必须是父类的指针或者引用
  3. 必须是虚函数

上面三个条件缺一不可,少一个你都看不到多态这美丽的属性


示例代码:

class Shoveler
{
public:
    virtual void foot()//条件3
    {
        cout<<"杂食,蔬菜,肉"<<endl;
    }

};
class Cat:public Shoveler
{
   public:
    virtual void foot()//条件3
    {
        cout<<"猫粮,鱼"<<endl;
    }

};
class Dog:public Shoveler
{
    public:
   virtual void foot()//条件3
    {
        cout<<"狗粮,骨头"<<endl;
    }
};
void WhatEat(Shoveler &sl)//条件2
{
  sl.foot();
}
int main()
{
    Shoveler d1;
    Cat d2;
    Dog d3;
     
   //调用
    WhatEat(d1);
    WhatEat(d2);
    WhatEat(d3);
}

结果:

在这里插入图片描述




什么虚函数?

在上一篇文章继承中,有一个概念叫菱形继承,可以用虚继承来解决。那你还记得那个关键字吗?virtual

大胆猜想

给继承时加virtual 就是虚继承,那么在函数前加virtual那不就是虚函数,我真聪明,emmm似乎确实如此




如何使用多态?

上述的代码大致你已经知道他的基本使用了,但是那个还不够,毕竟只是一个示范罢了 !!!!

条件2

在这里插入图片描述

虽然这里时条件,但是我还是好想知道为什么,指针和引用可以但是类型不可以呢

这里涉及到了底层,本文后面回、会讲解,就带着这个疑问继续阅读

那他是如何调用的虚函数达到多态的呢?

好家伙你这问到点上了,但是这还是涉及到底层。现在可以说这种达到多态的场景叫做覆盖,重写


条件3

在这里插入图片描述

多态条件补充

如果要构成多态,那么他的虚函数一定要 函数名,返回值,参数 都相同,当然返回值前加virtual




C++奇葩的设计(多态篇)

由上面刚刚补充的条件知道要构成多态虚函数需要满足函数名,返回值,参数 都相同,但是这里emmm出岔子了

岔子1:

返回值不同也可以构成多态,但是必须返回值是父子类(虽然我也不知道为啥有这个操作),且有一个好听的专有名词 协变

如图所示:
在这里插入图片描述

岔子2:

子类的虚函数可以不写。这里的话其实还比较好理解,或许是C++协会的大大害怕你会写忘了(有点贴心),其实重要的是继承了父类的虚拟函数了,因为虚函数继承是接口继承就是直接覆盖你的函数声明(但是建议还是写上为好,高质量c++编程🤪)

在这里插入图片描述

岔子3:

析构函数的虚函数可以名称不同,其实在上篇文章继承中说过,构造函数会被转换成destruct,所以其实还是同名

为啥析构函数还要是虚函数呀,好奇???


看下面这个例子
在这里插入图片描述

这种情况如果析构不构成重写的话,那么就会如图所示

在这里插入图片描述




一些看起来挺实用,但是感觉不太会用的操作

final

  1. 这个关键修饰的类不可继承
  2. 关键字修饰的虚函数不可以多态(重写,覆盖)

用法
在这里插入图片描述

override

关键修饰的虚函数如果没有实现多态就会报错,类似assert

用法
在这里插入图片描述

抽象类

虚函数声明后面 ? =0 就是抽象类,当是抽象类的时候是不可以实例化对象的,继承后如果子类不重写虚函数,那么子类也是抽象类

用法
在这里插入图片描述

抽象类就是一个媒介,或者他就是一个工具人,且只有被继承才可以使用,这里提个醒,他不可以实例化对象,但是可以创建指针引用,且类中也是可以有变量,好家伙真的工具类




多态的底层是如何实现的?

先看一些这道面试或许会问到的题(输出的是啥??)
在这里插入图片描述

运行结果
在这里插入图片描述

解释:

这里为啥是16呢?其实是虚函数在搞鬼,有了虚函数后这个类就会在开始多一个指针(虚表指针)博主编译器是在64平台下的,如图所示内存模型

在这里插入图片描述

虚表指针好熟悉,哦继承中不是也有一个虚基表指针,虚表指针是不是就是存虚函数的指针?

不得不说你还是很聪明,没错他确实就是存虚函数的指针(_vfptr),但是你要吧虚表和虚基表区分开来,这是菱形继承解决方案中的虚继承,虚基表存的父类元素的是偏移量




虚函数表

概念:

每个类都有属于自己的一个虚表(毕竟有各自的作用域),且这个这个类实例化的对象共用一张虚表,(虚函表存的这个函数的地址,而这个函数是存在公共代码段中的,所以一个类实例化的对象公用一张虚表


上述留下的坑

  1. 为啥只有指针和引用才支持多态
  2. 多态的实现

为啥只有指针和引用才支持多态?

因为如果用对象去接收的换,那么就只子类拷贝构造父类,但是指针和引用还是志向子类的内存空间的,如图所示的内存模型视图:

对象接收的情况
在这里插入图片描述

这里你或许会疑问为啥不把虚表拷贝构造呢?

每个类有属于自己唯一的虚表,且本类实例化对象共用一个虚表,如果拷贝(实例化对象就会有问题,它的虚表改变了,自己本类的虚函数访问不到)


父类指针或者引用的情况(其实也就是底层)

在这里插入图片描述




精准区分重载、重写,隐藏

重载

必须是同一作用域下函数名相同,但是参数列表不同,这个就是重载,有人会称他为静态的多态(在编译时就确定好函数的位置了)

重写

大前提条件就是在继承的前提下,父子类都有同名,同返回值,同参,虚函数,调用的时候一定是父类的指针或者引用

隐藏

也是在继承的前提下,只要父子类中有同名的函数不管参数和返回值是否一样,直接构成隐藏




面试或许会考察的题

请问下面程序的打印结果是啥?
在这里插入图片描述

答案

classA classB classC classD

解释

这里初始化看的不是构造函数列表,而是继承的顺序,编译器会优化A只初始化一次,至于为啥那就要看底层了


请问代码中的指针的偏移量(其实就是指针指向的位置)

A p1==p2==p3    B p1==p2!=p3   C p1==p3!=p2  D p1!=p2!=p3

在这里插入图片描述

答案

C

解释

如图所示:

在这里插入图片描述


请问下面打印的结果是啥?
在这里插入图片描述

答案

b->1

解释如图所示

在这里插入图片描述

如果这几道题对了恭喜,你这就是腾讯之前考过的笔试选择题




唠唠家常

这个就是面向对象的三大特性,其实理解起来也还好,也是全部语言通用的哦,那么就到这里吧!!!!

在这里插入图片描述

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-02-14 21:25:47  更:2022-02-14 21:25:58 
 
开发: 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/26 17:27:00-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码