类的多继承的派生类的虚表的一些问题

news/2024/10/23 3:10:26/

虚表保存的其实并不是虚函数的地址,而是他的到jmp地址。

上我们的操作代码

class A
{
public:virtual void func1(){}virtual void func2(){}int a = 1;
};class B
{
public:virtual void func1(){}virtual void func2(){}int b = 2;
};class C : public A, public B
{
public:virtual void func1(){printf("C::virtual void func1()\n");}virtual void func3(){}int c = 3;
};
int main()
{C cc;A* pa = &cc;B* pb = &cc;pa->func1();pb->func1();return 0;
}

问题一:C类有几个虚函数表。

问题一:C类的func3的虚函数地址存放在哪。

问题三:C类,A类与B类分别切片的时候虚函数func1地址不一样。

问题一:

进入调试模式

 我们可以清楚的看见我们的cc对象中继承的两个父类,而各各父类都有着自己的虚函数表。

cc的大小为20=A类(8)+B类(8)+成员变量c(4);//20已最大对称数对齐。


问题二

C::func3()保存在哪个虚函数表中呢?是A类还是B类还是都保存一份?

准备工具:打印函数地址与该地址函数调用,因为这三个函数的参数返回值一样所以可以使用函数指针来寻找我们func3的地址存放。因为在vs中虚表的最后有一个nullptr做表结尾,所以我们循环结束条件为地址是否为空。

typedef void(*Table)();
void printftable(Table table[])
{for (size_t i = 0; table[i] != nullptr; ++i){printf("table[%d]:%p    ", i, ble[i]);ble[i]();}
}
	printf("A类的虚函数表:\n");printftable((Table*)*(int*)pa);printf("=====================================\n");printf("B类的虚函数表:\n");printftable((Table*)*(int*)pb);

来解释一下我们的实参:

 运行程序:

根据运行结果我们找到了派生类的虚函数func3存放在A类虚函数表中,我们改变继承顺序

//class C : public A, public B
class C : public B, public A

会发现,我们的C类虚函数func3的存放于继承顺序有关。


问题三

在改一些代码

我们知道这里pa与pb的是cc的切片后的AB类指针。

pa和pb调用的func1都是被C类的func1重写的函数。所以调用打印的都是C::func1()。

回到问题一的调试模式,打开A与B的vfptr 。

既然打印的结果一样,但是我们看监视窗口中AB的虚函数表的func1函数地址不同,vs的bug吗?

但是上面问题二的打印也是说明了我们的切片后func1()的地址不同,但是调用的函数相同,不是AB基类的func1被C类重写了吗??这是为什么呢?

这里涉及了指针偏移的问题。首先需要看得懂汇编代码。

进入调试模式,对指针调用继续汇编查看

现在画图截图保存pa与pb的保存的地址

 pa中call eax指令继续jmp跳转

 继续jmp

 pa的跳转调用中,是直接跳转到我们的C类func1函数中。


 让我们看看pb怎么跳转函数的。

  pb中call eax指令jmp跳转

 继续jmp

 ecx是什么?是调用函数的对象地址。sub的意思是地址减8个字节

继续jmp

 继续jmp

会发现最后在sub-8后我们的jump

全局跳转图

 pb最后跳转依旧会来到pa的call位置0x00061343证明了,最后func1只有一份代码。

来解释一些为什么要pa与pb的虚函数表func1地址不同呢?应为pb的虚表中并不保存func1的jmp地址,而我们需要在第一次jmp后对ecx-8其实就是对我们的this(pb)-8个字节,改变指向到pa的虚函数表来调用A::中的func1真正的jmp地址。为什么pb不保存重写后的func1jmp地址?我其实吧也也想问问。


http://www.ppmy.cn/news/352547.html

相关文章

操作系统文献综述

摘 要 操作系统(Operating System,简称OS)是管理和控制计算机硬件与软件资源的计算机程序,是直接运行在“裸机”上的最基本的系统软件,任何其他软件都必须在操作系统的支持下才能运行。随着计算机技术的发展&#xff…

搭建国产化统信UOS操作系统虚拟机

统信UOS作为国产化操作系统的生力军,近年来异军突起。我使用过银河麒麟,飞腾麒麟,最后还是推荐给大家这款UOS操作系统。 一. 下载镜像 首先需要登录统信操作系统的官方网站https://www.chinauos.com/resource/download-home进行下载…

微信属于计算机操作系统吗,一款国产操作系统的微信电脑版使用体验

在中兴新支点操作系统下载试用了微信,用起来感觉还是很流畅很顺手的,比较简洁,但必要的基本功能都有了。 界面有点类似微信的网页版,整体主要是左右分布,左侧是功能栏和列表窗口,右边的是具体的内容展示窗口…

国产CPU架构、国产Linux操作系统及其国产数据库等关键应用

目录 国产CPU架构、国产Linux操作系统及其国产数据库等关键应用 1、CPU架构 1.1、基本常识 1.2、三大阵营整合为两大CPU阵营---CISC和RISC(以及RISC-V) 2、编译器 2.1、GCC编译器支持很多语言的编译,其中: 3、国产Linux的归…

[2020-11-30 ]国产化操作系统调研

近期,因为公司业务需要,服务器更换为国产操作系统,所以对国产系统的发展进行了一些调研。 首先是我国第一款国产操作系统–红旗 2000年成立北京中科红旗软件技术有限公司。 2001年的时候,在北京市政府的采购招标中,…

国产计算机系统哪个好,5大国产手机操作系统分析评测,你更中意谁?

5大国产手机操作系统分析评测,你更中意谁? 2018-11-29 20:03:28 3点赞 2收藏 5评论 在这个科技发展迅速的时代,手机与我们的生活是紧紧相依了,当前市场上,手机系统主要分为iOS系统和Android系统。我们国产手机几乎全都是Android系统,但由于安卓的自身功能的缺陷,国内很多…

又一国产桌面操作系统震撼发布!支持 Linux、Windows、安卓三大生态

点关注公众号,回复“1024”获取2TB学习资源! 6月18日消息,中科方德发布方德桌面操作系统5.0与兼容平台“方德鸳鸯火锅平台8.0”,基于国产x86硬件平台实现了对Linux、Windows、安卓三大应用生态支持。 据官方介绍,在兼容…

深度系统对Java的支持,国产操作系统深度deepin V20体验

1. 安装系统 国产操作系统deepin V20 bata版本已经发布。本人第一时间安装和体验。在犹豫很久之后,因为受到最新内核,高版本的bash和Python的诱惑,字体更加和谐等因素,选择升级系统。 个人比较喜欢全新安装,即直接重装系统。本人使用的小米笔记本,扩展了一个120G的SSD,用…