多态

大家应该都听过C++三大特性之一多态,那么什么多态呢?多态有什么用?通俗一点来讲->
多态性可以简单地概括为“一个接口,多种方法”,程序在运行时才决定调用的函数,它是面向对象编程 领域的核心概
念。当 多态 应用形参类型的时候,可以接受更多的类型。当多态用于返回值类型的时候, 可以返回更多类型的数据。多
态可以让你的 代码拥 有 更好的扩展性。
多态分两种分别为静态多态和动态多态:
静态多态:静态多态就是重载,因为是在编译期决议确定,所以称为静态多态。

动态多态:动态多态就是通过继承重写基类的虚函数实现的多态,因为是在运行时决议确定,所以称为动态多态。
而我们主要今天来看动态多态的问题。 比如我们来看下面的代码,就是简单的动态多态:
class Person
{
public:  virtual void BuyTickets()  {  cout << " 买票" << endl;  }  protected:  string _name;   // 姓名
};  class Student : public Person
{
public:  virtual void BuyTickets()  {  cout << " 买票-半价 " << endl;  }  protected:  int _num;   //学号
};  void Fun(Person& p)
{  p.BuyTickets();
}  void Test()
{  Person p;  Student s;  Fun(p);  Fun(s);
}
int main()
{  Test();  system("pause");  return 0;
}  


构成多态的四大条件: (缺一不可)
1.不在同一作用域(分别在父类和子类)

2.函数名相等/参数相等/返回值相同/(协变除外)

3.基类函数必须有virtual关键字

4.访问修饰符可以不同
具体多态是如何实现的?? 这里我们先从虚函数表这个知识点讲起,每一个带有虚函数的对象都会有 一个 虚函数表,虚
函 数表 里存的是函数指针,然后调用的时候,指针回去虚函数表里面访问查找。对于 这个知识点我的另外一个博客很详细
的讲 解到,大 家可以先看看这个: 深刻理解多态继承的基础虚函数类
然后我们来了解一下重写是什么东西?


重写的过程



如果这块还是不理解,你可以看我专门写虚函数那片博客,仔细看一定会看懂的.
接下来多态的原理我们就明白了吧. 发生重写之后,下一次父类指针指向我调用fun()函数的时候,它调用到的就是子类的
fun()函 数,其实多态就是这么简单,只要理解重写就理解多态. 虚函数表是我们必须掌握的一个知识点.

通过汇编来分析多态的实现

好了,我们继续往下走,刚刚我们从虚函数表这方面,探究了多态的实现,现在我们再从汇编的角度 再来看多态是如何
实现的。 我们来看一段新的代码:
class Person
{
public:  virtual void BuyTickets()  {  cout << " 买票" << endl;  }  protected:  string _name;   // 姓名
};  class Student : public Person
{
public:  virtual void BuyTickets()  {  cout << " 买票-半价 " << endl;  }  protected:  int _num;   //学号
};
void Fun(Person& p)
{  p.BuyTickets();
}  void Test()
{  Person p;  Student q;  Person* ptr = &q;  p.BuyTickets();  ptr->BuyTickets();
}
int main()
{  Test();  system("pause");  return 0;
}

打开我们的反汇编窗口:

这里我们看到用指向子类的父类类型指针调用BuyTickets函数和直接用对象调用汇编代码相差巨大, 一个只有2句话,一
个那 么长, 这是因为在发生多态时当你用指针调用时,系统不知道你要用哪一个函数,因为这里 有多态现象,所以系统只
能老实的 去虚函数表 里查找,所以 才会有这么多的代码,接下来我们来解释一 下这些汇编,来看看系统是调用虚表的。
这里我们就关心到了那四个红色的句子,可以看到这里一直都是想讲虚函数表的地址传给系统,然后再 传this指针,就
可以 调用哪 个函数了。蓝色的就是一个小知识~ 知道有这么个东西就好了.
虚函数是在基类中定义的,目的是不确定它的派生类的具体行为。例:
定义一个基类:class Animal//动物。它的函数为breathe()//呼吸。
再定义一个类class Fish//鱼 。它的函数也为breathe()
再定义一个类class Sheep //羊。它的函数也为breathe()
为了简化代码,将Fish,Sheep定义成基类Animal的派生类。

然而Fish与Sheep的breathe不一样,一个是在水中通过水来呼吸,一个是直接呼吸空气。所以基类不能确 定该如何定义
breathe ,所 以在基类中只定义了一个virtual breathe,它是一个空的虚函数。具本的函数在 子类中分别定义。程序一般
运行时,找到 类,如果 它有基类,再找它的基类,最后运行的是基类中的函数, 这时,它在基类中找到的是virtual标识
的函数,它就会再回 到子类中找同 名函数。派生类也叫子类。基类 也叫父类。这就是虚函数的产生和类的多态性 的体现。

一般情况下(没有涉及virtual函数),当我们用一个指针/引用调用一个函数的时候,被调用的函数是取决于这个指针

/引用的类型。即如果这个指针/引用是基类对象的指针/引用就调用基类的方法;如果指针/引用是派生类对象的指针/引

用就调用派生类的方法,当然如果派生类中没有此方法,就会向上到基类里面去寻找相应的方法。这些调用在编译阶段

就确定了。

当设计到多态性的时候,采用了虚函数和动态绑定,此时的调用就不会在编译时候确定而是在运行时确定。不在单独考

虑指针/引用的类型而是看指针/引用的对象的类型来判断函数的调用,根据对象中虚指针指向的虚表中的函数的地址来

确定调用哪个函数。

现在我们来一个小练习:

#include<iostream>
#include<Windows.h>
using namespace std;  class A
{
public:  void foo()  {  printf("1\n");  }  virtual void fun()  {  printf("2\n");  }
};
class B : public A
{
public:  void foo()  {  printf("3\n");  }  void fun()  {  printf("4\n");  }
};
int main(void)
{  A a;  B b;  A *p = &a;  p->foo();  p->fun();  p = &b;  p->foo();  p->fun();  system("pause");  return 0;
}

这道题的运行结果分别是 1 2 1 4,,现在我们来分析为什么?

首先当一个父类类型指针指向父类时,我们应该知道这里没有多态,该怎么调用就怎么调用,所以调用了父类里面的

foo函数和fun函数。现在我们重点来看后面这个,现在B继承了A,我们先判断这里是否有多态现象(1.父类和子类是

否有重写现象

2.是否有父类类型的指针指向子类),现在很明显子类的fun函数重写了父类的fun函数,所以现在p->fun()调用的就

是子类的fun函数,然后foo函数,根本不构成多态,所以这里指针类型是什么那个对象就按那个对象调用。总结一下

当你碰到关于继承的问题,首先判断它里面是否有多态现象,如果没有那就根据指针/引用类型调用。如果有多态的

话,一定要注意根据指针/引用的指向对象判断。

C++ —面向对象之多态的实现与应用相关推荐

  1. 12 Java面向对象之多态

    JavaSE 基础之十二 12 Java面向对象之多态 ① 多态的概念及分类 多态的概念:对象的多种表现形式和能力 多态的分类 1. 静态多态:在编译期间,程序就能决定调用哪个方法.方法的重载就表现出 ...

  2. swift面向对象之多态与继承

    swift面向对象之多态与继承 1.多态 运行时多态 运行时多态的要点 1.要有继承关系的存在 2.子类要重写父类的方法 3.父类类型的引用指向子类实例 2.继承 1.继承的注意 继承可以用于类而不能 ...

  3. Golang笔记-面向对象编程-多态/类型断言

    面向对象编程-多态 基本介绍 变量(实例)具有多种形态.面向对象的第三大特征,在 Go 语言,多态特征是通过接口实现的.可 以按照统一的接口来调用不同的实现.这时接口变量就呈现不同的形态. 快速入门 ...

  4. Java 面向对象:多态的理解

    Java 面向对象:多态的理解 一.多态的定义 一个对象的实际类型是确定的,但可以指向引用对象的类型可以有很多(父类,有关系的类) 操作符的多态 +可以作为算数运算,也可以作为字符串连接 类的多态 父 ...

  5. python面向对象三大特性_Python面向对象之多态原理与用法案例分析

    本文实例讲述了Python面向对象之多态原理与用法.分享给大家供大家参考,具体如下: 目标 多态 面向对象三大特性 封装 根据 职责 将 属性 和 方法 封装 到一个抽象的 类 中 定义类的准则 继承 ...

  6. python中的多态用法_Python面向对象之多态原理与用法案例分析

    本文实例讲述了Python面向对象之多态原理与用法.分享给大家供大家参考,具体如下: 目标 多态 面向对象三大特性 封装 根据 职责 将 属性 和 方法 封装 到一个抽象的 类 中 定义类的准则 继承 ...

  7. Python面向对象编程---多态

    Python面向对象编程-多态 定义: 是一种使用对象的方式,子类重写父类的方法(非必须),调用不同子类对象的相同父类方法,可以产生不同的执行结果,简言之就是:传入不同的对象,产生不同的结果. 好处: ...

  8. Java面向对象之多态(来源于身边的案例)

    2019年1月3日 星期四 Java面向对象之多态(来源于身边的案例) 1. 为什么要用多态? 1.1 多态是面向对象的三大特性之一 1.2 多态是基于接口设计的模型 1.3 多态具有横向扩展特性 1 ...

  9. Java面向对象:多态——基于继承的向上转型、方法重写、动态绑定

    Java面向对象:多态 1.多态的概念 2.向上转型和向下转型 (1)向上转型 (2)向下转型 3.方法重写 4.动态绑定与静态绑定 5.多态的优缺点 ======================== ...

  10. Python学习 - 面向对象之多态

    Python学习 - 语法入门:https://blog.csdn.net/wanzijy/article/details/125287855 Python学习 - 数据类型:https://blog ...

最新文章

  1. golang struct 转map 及 map[string]*Struct 初始化和遍历
  2. Linux du命令和df命令区别
  3. 江西计算机一级考试教程,江西省2019年下半年计算机一级考试复习教程:计算机基础及MS Office应用上机指导...
  4. 如何用VS2005制作Web安装程序
  5. 在WEB开发的时候导入各种jar包
  6. python可打印字符_测试一个python字符串是否可打印
  7. Windows+Python3.7下自动生成requirements.txt文件
  8. 计算机图形学与混合现实研讨会GAMES: Graphics And Mixed Environment Seminar
  9. 生活中运筹学的3个小案例_10个“乡村庭院”设计案例,生活在乡下,家家都有自己的小庭院...
  10. java删除指定文件后重新建立文件系统_java file 操作之创建、删除文件及文件夹...
  11. 数字后端概念——MIM cell
  12. 常识性知识,高速快捷知识
  13. jquery获取元素(父级的兄弟元素的子元素)
  14. 居家办公的团队协作模式改进思考
  15. python中wheel什么意思_某个wheel(.whl)包的依赖关系是什么?
  16. 每日小技巧——教你用一行Python代码去除照片背景
  17. win+shift+s截图保存在哪_Windows 被冷落的 WIN 键,其实比你想的更好用
  18. 湖南工程学院计算机与通讯学院肖鹏,基于区间分析无迹粒子滤波的移动机器人SLAM方法...
  19. 安卓系统再曝高危漏洞!大部分手机都可能被黑客控制
  20. 李彦宏提案的思路:基于实践、崇尚技术、关注民生

热门文章

  1. Codeforces Kitchen Plates
  2. 黑盒测试、白盒测试、单元测试、集成测试、系统测试、验收测试的区别与联系
  3. 无线路由器穿墙能力浅析
  4. idea中使用git合并代码
  5. 常用的霍尔效应测试方案
  6. ChatGPT颠覆的第三个行业-教育领域
  7. 自定义语法作色(myBase笔记软件一)
  8. Android设置Activity透明背景样式
  9. java“智慧食堂”系统springbootvueweb
  10. 烽火HG680-KA_KB_GK国科6323_强刷卡刷固件包