多态分为两类
1.静态多态:函数重载和运算符重载属于静态多态,复用函数名
2.动态多态:派生类和虚函数实现运行时多态

静态多态和动态多态区别:
1.静态多态的函数地址早绑定,编译阶段确定函数地址
2.多态多态的函数地址晚绑定,运行阶段确定函数地址

首先让我们看这段代码:

#include <iostream>
using namespace std;class Animal {public:void speak() {cout << "动物在说话" << endl;}
};class Cat : public Animal {public:void speak() {cout << "小猫在说话" << endl;}
};void dospeak(Animal &animal) {animal.speak();}void test01() {Cat cat;dospeak(cat);}int main() {test01();system("pause");return 0;
}

结果为:动物在说话

我们想要的是猫在说话,可最后输出的结果却是动物在说话,为什么呢?

因为dospeak函数地址早绑定了,在编译阶段就确定了函数地址

那么我们要怎样做才能让猫说话呢?
非常简单,就是利用动态多态,就是要让dospeak函数的地址晚绑定(在运行阶段进行绑定),我们只要在父类的同名speak函数前面加virtual关键字,现在speak函数就变成了虚函数,就解决了上述问题。

代码如下:

#include <iostream>
using namespace std;class Animal {public:virtual void speak() {cout << "动物在说话" << endl;}
};class Cat : public Animal {public:void speak() {cout << "小猫在说话" << endl;}
};void dospeak(Animal &animal) {animal.speak();}void test01() {Cat cat;dospeak(cat);}int main() {test01();system("pause");return 0;
}

结果为:猫在说话


重写的概念:
1.函数的返回类型相同
2.函数名相同
3.参数列表相同

动态多态的满足条件:
1.有继承关系
2.子类要重写父类的虚函数

动态多态的使用:
父类的指针或引用指向子类的对象

现在我们来看看多态的原理,首先我们看一下下面这段代码:

#include <iostream>
using namespace std;class Animal {public:void speak() {cout << "动物在说话" << endl;}
};class Cat : public Animal {public:void speak() {cout << "小猫在说话" << endl;}
};void dospeak(Animal &animal) {animal.speak();}void test01() {cout << "size of Animal = " << sizeof(Animal) << endl;}int main() {test01();system("pause");return 0;
}

结果为size of Animal = 1

现在我们在Animal的speak函数前面加上virtual,写成多态的形式,结果又是多少呢?

#include <iostream>
using namespace std;class Animal {public:virtual void speak() {cout << "动物在说话" << endl;}
};class Cat : public Animal {public:void speak() {cout << "小猫在说话" << endl;}
};void dospeak(Animal &animal) {animal.speak();}void test01() {cout << "size of Animal = " << sizeof(Animal) << endl;}int main() {test01();system("pause");return 0;
}

结果为:size of Animal = 4
这说明,加了virtual后,这个类的内部结构发生了改变。
那到底多了什么东西,导致这个类变成了4个字节呢?

结果:
多了指针。
现在让我们看看这其中发生的变化,
首先我们要知道:
vfptr - 虚函数(表)指针
v - virtual
f - function
ptr - pointer


vftable - 虚函数表
v - virtual
f - function
table - table


现在让我们看看Animal类内部结构:

Cat内部结构:

当子类重写父类的虚函数时,子类中的虚函数表内部会替换成子类的虚函数地址
也就是说,当我们往父类Animal的speak函数前面加上virtual时,Cat的内部结构就会变成这样:


当父类中的指针或者引用指向子类对象的时候,就发生了多态。

我们就相当于写了这样一段代码:
Animal &animal = cat;
animal,speak();
当我们调用animal的speak函数时,由于指向的是Cat对象,所以编译器会从Cat的虚函数表中找speak函数,就相当于在运行阶段发生了多态。

原理:
由于我们写了一个虚函数,类的内部发生了结构的改变,多了一个虚函数表指针,指向虚函数表,虚函数表内部写的是虚函数的函数入口地址,当子类重写了虚函数表,会把自身的虚函数表给替换掉,这里的替换就是Cat类中发生的替换。

C++多态的基本语法与原理剖析相关推荐

  1. ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件)

    在上一节(ASP.NET Core 运行原理剖析1:初始化WebApp模版并运行)中提到ASP.NET Core WebApp 必须含有Startup类,在本节中将重点讲解Startup类以及Midd ...

  2. oracle 日志 性能,Oracle日志的性能介绍及原理剖析-Oracle

    Oracle日志的性能介绍及原理剖析 一)一致性和性能 日志是所有数据库的一个很核心的内容很重要 它关系到数据库的数据的一致性 目前大家在使用的我们可看到的有几个数据库 有oracle.sqlserv ...

  3. react16常见api以及原理剖析

    Vue 与 React 两个框架的粗略区别对比 Vue 的优势包括: 模板和渲染函数的弹性选择 简单的语法及项目创建 更快的渲染速度和更小的体积 React 的优势包括: 更适用于大型应用和更好的可测 ...

  4. React16常用api解析以及原理剖析

    React16常用api解析以及原理剖析 目录 Vue 与 React 两个框架的粗略区别对比 react 16 版本常见 api react 生命周期 react 事件机制 react.Compon ...

  5. 【java基础18:方法覆盖与多态】什么时候使用方法覆盖 toString方法的覆盖 多态的基础语法与作用 向上/向下转型

    目录 方法覆盖Override 多态 方法覆盖Override 方法覆盖初体验,什么样的程序要方法覆盖 /*当前程序存在的问题(设计上的问题)??鸟儿在执行move()方法的时候,最好输出的结果是:& ...

  6. socket之send和recv原理剖析

    socket之send和recv原理剖析 1. 认识TCP socket的发送和接收缓冲区 当创建一个TCP socket对象的时候会有一个发送缓冲区和一个接收缓冲区,这个发送和接收缓冲区指的就是内存 ...

  7. fastText的原理剖析

    fastText的原理剖析 1. fastText的模型架构 fastText的架构非常简单,有三层:输入层.隐含层.输出层(Hierarchical Softmax) 输入层:是对文档embeddi ...

  8. lua游戏脚本实例源码_Lua与其他宿主语言交互原理剖析

    Lua与其他宿主语言交互原理剖析 题外话:今天周末,刚好在家有时间就把我这次项目组内部分享的文章贴出来,分享给大家,同时也方便以后自己翻阅. 一. Lua简介 目标:Lua语言本身是用C语言来编写开发 ...

  9. Go语言底层原理剖析

    作者:郑建勋 出版社:电子工业出版社 品牌:博文视点 出版时间:2021-08-01 Go语言底层原理剖析

最新文章

  1. 嵌入式Linux下跑自整定pid,告诉过你PID很重要,你不听
  2. GPUImage简单说明
  3. NFV业务技术说明—Vecloud微云
  4. Nginx的正向代理与反向代理
  5. 蓝牙耳机和蓝牙鼠标相互干扰_TWS蓝牙耳机哪个牌子好?主流无线蓝牙耳机推荐...
  6. Java中 SPI的使用
  7. Java中System.setProperty()用法
  8. 设置 Xcode 自动生成代码片段
  9. .Netcore 2.0 Ocelot Api网关教程(番外篇)- Ocelot v13.x升级
  10. C#后台调用oracle存储过程,参数传入的是clob字段,怎样处理
  11. 数组中其余的排除_带你一步步精通数组之十五:数组的计算规律之五
  12. cuSPARSE库:(八)cusparseGetStream()
  13. 肌肉男比常人多了哪些烦恼?
  14. 记录——《C Primer Plus (第五版)》第九章编程练习第三题
  15. win10家庭版无法安装mysql_Win10安装MySQL
  16. 【转】LPCTSTR,LPWSTR, PTSTR, LPTSTR区别
  17. Windows10系统打开程序应用提示『不支持此接口』的解决方案
  18. 最有效率地戒掉晚睡强迫症(熬夜强迫症、假象失眠症等等)
  19. 四大里snr是什么职位_四大会计师事务所人员流动性高的原因是什么?
  20. websphere html乱码,websphere 乱码问题

热门文章

  1. java之DocumentBuilderFactory解析xml
  2. linux c之使用共享内存实现进程间通信
  3. linux之路由知识之ip route 命令中的疑惑
  4. 求数组里面的最大值和最小值
  5. SSH基本原理和免密码登录
  6. for循环批量写文件 shell_shell脚本:for循环批量重命名带空格文件名的文件
  7. linux docker nginx,CentOS7上Docker简单安装及nginx部署
  8. 人生没有对与错,只是选择不同
  9. 资料分享 | 数学建模竞赛备战大全
  10. 无法使用此安装程序来安装 .net framework_NuGet是什么?理解与使用(上)