详解C++多态

多态前言:

什么是多态?

多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。

不同的对象执行同一段代码会调用不同的函数
在这里插入图片描述

目录

  • 如何才能实现多态
    • 什么是重写?
    • 重写、重载、重定义对比
  • 多态的运行原理
  • 虚表深入探索
    • 单继承虚表
    • 多继承虚表

如何才能实现多态

  1. 派生类必须对基类的函数进行重写
  2. 必须通过基类的指针或者引用来调用函数
  3. 被调用的函数必须是虚函数

什么是重写?

重写:两个函数的参数列表,函数名,返回值必须全部相同

重写的两个例外:

  1. 派生类的重写虚函数可以不加virtual(建议大家自己写的时候加上)
  2. 协变:返回的值可以不同,但要求返回值必须是父子关系的指针或引用(不常用)

举例1:
在这里插入图片描述
在这里插入图片描述
举例2:
在这里插入图片描述

重写、重载、重定义对比

在这里插入图片描述

多态的运行原理

我们来算下Person和Student的大小:
在这里插入图片描述
不是我们预期的4和8,为什么呢?

在Person对象里有一个虚函数表(指针数组),指向代码段的函数地址

注意 :派生类对象自己不会单独产生虚函数表,派生类的表是继承基类的。

为什么必须是父类的指针或引用,而不是子类的?

切片可使父类的指针既指向子类对象又可以指向父类对象

为什么父类的对象不能实现多态,只能父类的指针或引用实现?

因为子类赋值给父类对象的时候,父类并不会拷贝子类的虚函数表

多态运行原理:

  1. 按编译规则查找函数,找到了在看该函数是否构成重载或多态
  2. 若构成多态,则在运行时才会取函数地址,运行时通过指针找出对象, 并通过对象的虚函数表中找到要调用和函数地址

虚表深入探索

虚表在内存的哪个位置?

虚表在vs下的存储是代码段里

如何验证??

可以通过对地址的分析来确定,下图中验证了虚表里常量区的更近,所以在vs下可以看出,虚表存储在常量区
在这里插入图片描述

单继承虚表

子类的虚表由以下三部分构成

  1. 会拷贝父类虚表
  2. 子类重写的函数会覆盖父类函数的地址
  3. 再添加自己的虚函数

由于编译器监视窗口的优化,我们不能直接看监视窗口里虚表的内容。则需要我们自己打印虚表
如何打印虚表

思路:取出b、d对象的头4bytes,就是虚表的指针,前面我们说了虚函数表本质是一个存虚函数指针的指针数组,
这个数组最后面放了一个nullptr
1.先取b的地址,强转成一个int的指针
2.再解引用取值,就取到了b对象头4bytes的值,这个值就是指向虚表的指针
3.再强转成VFPTR
,因为虚表就是一个存VFPTR类型(虚函数指针类型)的数组。
4.虚表指针传递给PrintVTable进行打印虚表
5.需要说明的是这个打印虚表的代码经常会崩溃,因为编译器有时对虚表的处理不干净,虚表最后面没有放nullptr,导致越界,这是编译器的问题。我们只需要点目录栏的-生成-清理解决方案,再编译就好了。

在这里插入图片描述

多继承虚表

在这里插入图片描述
为什么这里Derive虚函数表里两个func1()的函数指针不同?

你们发没发现基类指针调用重写函数,传的是基类的this指针,而在重写函数里确可以无差错的调用派生类里的成员

如:在这里插入图片描述

明明B*的this在_a成员的下面却可以调用_a成员。

实际上基类指针调用重写函数,虽然传的是基类的this指针,最后编译器会将this指针处理成派生类的指针,使之能正确的访问到派生类里的每个成员。

最后表现出了Derive虚函数表里两个func1()的函数指针不同

若要追究编译器如何将基类的this指针处理成派生类的this指针,大家可以去看看汇编,简单来说就是call时对地址的封装,让基类的this指针减去第一个继承类的大小,this就指向了派生类的首地址,就可以当作派生类的this地址了

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值