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++多态底层剖析 -> 正文阅读

[C++知识库]C++多态底层剖析

多态的概念

多态是C++三大面向对象特性之一
多态分为两类:
1.静态多态:重载就是静态多态
2.动态多态:派生类和虚函数实现运行时多态

静态多态和动态多态区别:静态多态的函数地址是在编译时就确定的,而动态多态函数地址在运行时才确定。

以下是多态的案例:

//动物类
class Animal
{
public:
	//动物运动函数
	virtual void move()
	{
		cout << "动物在运动" << endl;
	}
};

//鱼类继承动物类
class Fish : public Animal
{
public:
	//鱼类运动函数重写
	void move()
	{
		cout << "鱼在游" << endl;
	}
};

//狗类继承动物类
class Dog :public Animal
{
public:
	//狗类运动函数重写
	void move()
	{
		cout << "狗在跑" << endl;
	}
};

//通过函数调用类内函数
void doMove(Animal& animal)
{
	animal.move();
}
int main()
{
	Fish fish;
	doMove(fish);
	return 0;
}

运行后如图
在这里插入图片描述
当我们通过Animal指针调用同名函数时,最后调用的函数确是派生类(鱼类)的函数,这就是动态多态了。

多态底层原理

1.virtual修饰的函数叫做虚函数。
2.存在虚函数的类内会有一个指针,叫做vfptr(虚函数指针),这个指针维护一个表,叫做虚函数表,这张表存放着虚函数的地址,编译器通过这个指针去寻找和确定虚函数。
3.虚函数表由编译器维护。
4.类内的虚函数会被加入虚函数表中。

举例论证

下面我们通过几个例子,来探索这个虚函数指针和虚函数表的运行规则。
虚函数表就像是一张地图,通过虚函数指针,可以找到需要使用的虚函数。
回到上面的代码案例,我们来探讨为什么通过基类指针指向派生类调用虚函数会调用到派生类中的函数。

我们通过VS自带的Develoer Command Prompt for VS 来观察单个类的布局
首先把基类中的virtual去掉如图所示
在这里插入图片描述
这时候观察Animal类的布局,之后再观察有虚函数时Animal的布局
在这里插入图片描述
不出所料,总大小是一个字节,这是因为类和函数是分别存储的,所以大小和空类是一样的,现在我们把virtual加上去以后再观察单个类布局,如图所示:
在这里插入图片描述
在这里插入图片描述
这时候我们看了Animal与之前的不同
1.Animal空间大小变成了4个字节,还出现了名为vfptr的东西。
2.vfptr就是虚函数指针的英文缩写,因为是32位平台,指针的空间大小是4个字节,刚好对应类中的4个字节。
3.还出现了一张表,表中有move函数,这张表就是指针维护的虚函数表

至此,我们继续研究Fish派生类的类布局,一样通过Develoer Command Prompt for VS:
在这里插入图片描述
我们可以知道,当FIsh继承了Animal后,这个虚指针也是在的,它维护的是Fish类,所以,当派生类重写虚函数时,这个函数实际上也是虚函数,它有虚函数指针和虚函数表,来观察这个维护的虚函数表,它里面装的是 Fish类自己的虚函数,而不是继承下来的Animal中的move函数。

到这里,我们来回顾一下这个程序运行的过程,首先我们通过基类指针(Animal&)去调用派生类的函数,这时候调用出来的确实是派生类中的"鱼在游",这是因为当调用虚函数时,实际上是vfptr去找vftable中该函数地址的过程,那么哪怕你是通过基类去调用的函数,它的类实际上还是派生类,vfptr还是在此类中的vftable中去找该名字的函数,于是找到了&Fish::move,这时候调用出来的就是Fish下的move函数了。

总结

要发生动态多态,那么必须满足两点:
1.有继承关系。
2.子类重写父类的虚函数。
动态多态的本质就是函数运行时再通过vfptr指针去访问对应vftable中的函数地址从而调用函数。

希望大佬指点,多多点赞!在这里插入图片描述

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-14 13:50:50  更:2021-08-14 13:51:28 
 
开发: 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年5日历 -2024/5/21 3:42:38-

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