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

news2025/2/12 3:41:27

虚表保存的其实并不是虚函数的地址,而是他的到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.coloradmin.cn/o/640009.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SAP HANA内存

用着用着HANA 数据库就慢了,原因都出在内存。 内存不足无非几个原因: 1.你的机器物理内存不足,这个好办,花钱扩。 2.你的HANA License容量不足,这个也好办,申请更大容量的内存License 3.你机器分配给HAN…

爬虫案例-使用Session登录指定网站(JS逆向AES-CBC加密+MD5加密)

总体概览:使用Session登录该网站,其中包括对password参数进行js逆向破解 (涉及加密:md5加密AES-CBC加密) 难度:两颗星 目标网址:aHR0cHM6Ly93d3cuZnhiYW9nYW8uY29tLw 下面文章将分为四个部分…

在后大流行时代利用Airbnb实现逆周期增长

回望近十年共享经济的发展历程,谁也不曾想到,最被看好的共享经济代表Uber竟在连年亏损后忍痛IPO,上市首日即破发,而主打「互联网房地产」模式的独角兽WeWork则上市失败,迅速失血,一度走到破产边缘。作为“共…

模型剪枝:Network Slimming剪枝实战

本文来自公众号“AI大道理” ​ Network Slimming剪枝是比较广泛的一种模型剪枝方法,作者来自清华大学、英特尔中国实验室、复旦大学和科内尔大学。 1、Network Slimming剪枝理论 Network Slimming剪枝是结构性剪枝,是通道剪枝,是静态剪枝…

mac安装hive_20230609

竟然是今年第一篇 hhhh 过两天把上半年的东西梳理好的话 陆续放上来吧~ 公司本地测试环境的hive版本不支持不等式关联操作,而现在用hive也比较多,所以在本地装了一个hive,主要写一下大致步骤和过程中遇到的问题~&#…

win10任务栏卡死解决

现象: win10 更新后,开机任务栏卡死,点开始反应,设置页面无法打开。 原因: 原因是Win10更新的任务栏资讯和兴趣,而资讯和兴趣是Edge浏览器的,该服务器是在国外,国内的网络加载不出来…

【lvs集群】HAProxy搭建Web集群

HAProxy搭建Web集群 一、 HAProxy简介1.1HAProxy主要特性1.2HAProxy负载均衡策略非常多,常见的有如下8种1.3LVS、Nginx、HAproxy的区别1.4常见的Web集群调度器 二、Haproxy搭建 Web 群集haproxy服务器部署节点服务器部署 三、定义监控页面与定义日志3.1定义监控页面…

stm32f103最小系统板详细介绍

一.什么是单片机最小系统 常见的单片机最小系统为单片机能独立运行程序及控制外围电路的最简单电路,主要由单片机、晶振电路、复位电路三部分构成。Stm32f103c8t6也不例外,构成最小的运行电路也需要以上三部分。 Stm32f103最小系统板原理图如下&#xf…

初始Sentinel(Sentinel的简单介绍及项目整合)

前言:大家好,我是小威,24届毕业生,在一家满意的公司实习。本篇文章将详细介绍Sentinel的概念,优点,与Hystrix的对比以及微服务中整合Sentinel,后续文章将详细介绍Sentinel的细节部分。 如果文章…

分享几个关于AI的网站

分享几个关于AI的网站 AI文本 ChatGPT:https://chat.openai.com/ NotionAI:https://www.notion.so/product/ai A.I. Data Sidekick:AI工具编写 SQL、文档等的速度提高10倍https://www.airops.com/ Writesonic:人工智能写作辅助工…

CSS基础学习--7 fonts字体

一、CSS 字体 CSS字体属性定义字体系列,加粗,大小,文字样式。 二、字体系列 font-family 属性设置文本的字体系列 font-family 属性应该设置几个字体名称作为一种"后备"机制,如果浏览器不支持第一种字体,…

Haproxy的应用

Taproxy 一、Haproxy的原理Haproxy的主要特性Haproxy八种负载均衡策略LVS、Nginx、Haproxy的区别 二、搭建web群集 一、Haproxy的原理 Haproxy是可提供高可用性,负载均衡以及基于TCP和HTTP应用的代理,是免费、快速并且可靠的一种解决方案。Haproxy非常适…

电脑提示vcruntime140_1.dll丢失怎么修复?

本修复教程操作系统:Windows系统 vcruntime140_1.dll是电脑文件中的dll文件(动态链接库文件)。如果计算机中丢失了某个dll文件,可能会导致某些软件和游戏等程序无法正常启动运行,并且导致电脑系统弹窗报错。 在我们打…

FPGA基础知识-模块和端口

目录 学习目标 学习内容 端口 端口列表 端口声明 端口链接规则 学习时间 总结 学习目标: 1.说明Verilog 模块定义中的各个组成部分,例如模块名、端口列表、参数、变址声明、数据流描述语句、行为语句、调用(实例引用》其他模块以及任务…

Java网络开发(Filter过滤器)—— tomcat的过滤器 编码控制 + 网页权限控制

目录 引出1.过滤器简介2.用过滤器实现全局编码控制(1)导包import javax.servlet.*;(2)如果是tomcat8.5,要把3个方法都实现(3)代码如下,要点:放行,chain.doFil…

Bug小能手系列(python)_7: BertTokenizer报错 Connection reset by peer

ConnectionResetError: [Errno 104] Connection reset by peer 0. 错误介绍1. 解决思路1.1 添加代码 force_downloadTrue1.2 删除缓存1.3 科学上网1.4 线下下载 2. 解决方法2.1 清除缓存2.2 线下下载模型(强烈建议) 3. 总结 0. 错误介绍 当使用transfor…

4.将图神经网络应用于大规模图数据(Cluster-GCN)

到目前为止,我们已经为节点分类任务单独以全批方式训练了图神经网络。特别是,这意味着每个节点的隐藏表示都是并行计算的,并且可以在下一层中重复使用。 然而,一旦我们想在更大的图上操作,由于内存消耗爆炸&#xff0c…

【Python 生成器与迭代器】零基础也能轻松掌握的学习路线与参考资料

一、Python生成器与迭代器概述 Python是一种高级编程语言,其中非常重要的概念就是生成器和迭代器。Python生成器和迭代器联合使用,能够实现高效的迭代操作,避免增加额外的内存消耗,同时提高代码的可读性。Python中常见的生成器和…

单机多节点 elasticsearch 集群安全认证

es 版本:7.6.2 部署环境:CentOS Linux release 7.6.1810 (Core) 一:生成 ca 证书 cd 到 es 的安装目录,并执行下面的命令来生成 ca 证书: ./bin/elasticsearch-certutil ca Elasticsearch碰到第一个直接回车&#xf…

面试专题:Mysql

1.说说自己对于 MySQL 常见的两种存储引擎:MyISAM与InnoDB的理解 关于二者的对比与总结: 1.count运算上的区别:因为MyISAM缓存有表meta-data(行数等),因此在做COUNT(*)时对于一个结构很好的查询是不需要消耗多少资源的…