多态 虚函数表深度剖析 纯干货讲解(2)

💯 博客内容:多态

😀 作  者:陈大大陈

🚀 个人简介:一个正在努力学技术的准C++后端工程师,专注基础和实战分享 ,欢迎私信!

💖 欢迎大家:这里是CSDN,我总结知识和写笔记的地方,喜欢的话请三连,有问题请私信 😘 😘 😘

目录

虚函数存在哪里? 

虚函数的地址一定会被放进虚函数表吗?

结论 


 

虚函数储存在哪里? 

 首先思考一个问题,虚函数存在哪里?

虚函数和普通函数一样,存在代码段,同时将虚函数地址存了一份到虚函数表。

那虚函数表存在哪里?

存在栈区出了作用域会销毁,堆区需要动态分配内存,都不现实。

经过测试,虚表是储存在常量区的代码段的,跟常量很接近。

虚函数的地址一定会被放进虚函数表吗?

第二个问题,虚函数的地址一定会被放进虚函数表吗?

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
class Base {
public:
	virtual void func1() { cout << "Base::func1" << endl; }
	virtual void func2() { cout << "Base::func2" << endl; }
private:
	int a;
};

class Derive :public Base {
public:
	virtual void func1() { cout << "Derive::func1" << endl; }
	virtual void func3() { cout << "Derive::func3" << endl; }
	virtual void func4() { cout << "Derive::func4" << endl; }
	void func5() { cout << "Derive::func5" << endl; }
private:
	int b;
};

class X :public Derive {
public:
	virtual void func3() { cout << "X::func3" << endl; }
};

int main()
{
	Base b;
	Derive d;
	X x;

	Derive* p = &d;
	p->func3();

	p = &x;
	p->func3();

	return 0;
}

如图,这种情况三个虚表指针都没有存储func3的地址。 

难道是func3的地址没有存储吗?
并不是这样,监视窗口看到的内容是经过编译器处理的。

我们合理怀疑编译器骗我们。

打开内存监视窗口,我们高度怀疑后面两个地址是被隐藏的两个虚函数的地址。 

虚表储存在类的前四个字节,我们就取这四个字节打印出来。

typedef void (*VFUNC) ();
void PrintVFT(VFUNC a[])
{
	for (size_t i = 0; a[i] != 0; i++)
	{
		printf("[%d]:%p\n", i, a[i]);
	}
	cout << endl;
}
int main()
{
	//void (*f)();
	VFUNC f2;
	Base b;
	PrintVFT((VFUNC*)(*((int*)&b)));
	return 0;
}

看不明白的老铁可以看看上面的图。 

传入base类打印,结果如下。

不对劲,清理解决方案之后再重新生成解决方案,再次编译。

 

第一次编译器出了bug,没有在虚表后标识上0,第二次就好了。 

比葫芦画瓢打印一下d和x,但是此时仍然不能确定。 

终于到了放终结技的时候了,我们可以在打印的时候同时调用函数。

上面我们埋下了伏笔,在命令行窗口会打印出来调用函数的信息。

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
class Base {
public:
	virtual void func1() { cout << "Base::func1" << endl; }
	virtual void func2() { cout << "Base::func2" << endl; }
private:
	int a;
};

class Derive :public Base {
public:
	virtual void func1() { cout << "Derive::func1" << endl; }
	virtual void func3() { cout << "Derive::func3" << endl; }
	virtual void func4() { cout << "Derive::func4" << endl; }
	void func5() { cout << "Derive::func5" << endl; }
private:
	int b;
};

class X :public Derive {
public:
	virtual void func3() { cout << "X::func3" << endl; }
};

//int main()
//{
//	Base b;
//	Derive d;
//	X x;
//
//	Derive* p = &d;
//	p->func3();
//
//	p = &x;
//	p->func3();
//
//	return 0;
//}
typedef void (*VFUNC) ();
void PrintVFT(VFUNC *a)
{
	for (size_t i = 0; a[i] != 0; i++)
	{
		printf("[%d]:%p\n", i, a[i]);
		VFUNC f = a[i];
		f();
	}
	cout << endl;
}
int main()
{
	//void (*f)();
	VFUNC f2;
	Base b;
	Derive d;
	X x;
	PrintVFT((VFUNC*)(*((int*)&b)));
	PrintVFT((VFUNC*)(*((int*)&d)));
	PrintVFT((VFUNC*)(*((int*)&x)));
	return 0;
}

运行结果如下。

结论 

可算对上了捏!

 此时此刻,我们终于可以骄傲地回答上面的问题!

所有的虚函数都会被放进虚表吗?

是的!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/116812.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

两种MySQL OCP认证应该如何选?

很多同学都找姚远老师说要参加MySQL OCP认证培训&#xff0c;但绝大部分同学并不知道MySQL OCP认证有两种&#xff0c;以MySQL 8.0为例。 一种是管理方向&#xff0c;叫&#xff1a;Oracle Certified Professional, MySQL 8.0 Database Administrator&#xff08;我考试的比较…

Mac安装VMware

去官网下载一下VMware Download VMware Fusion | VMware | SG 下载完成之后&#xff0c;打开直接闪退&#xff0c;参考这篇文章解决 解决macOS13安装Fusion13闪退的问题-CSDN博客 然后即可成功顺行

「视频编码软件」Media Encoder(Me) 2024 Mac/win中文版下载安装

Adobe Media Encoder(Me) 2024是一款专业的视频编码工具&#xff0c;它可以将各种视频格式进行转换、压缩和编码&#xff0c;以满足不同媒体平台和设备的需求。 以下是 Media Encoder 2023 的主要功能和新增功能&#xff1a; 视频编码和转换&#xff1a;支持将各种视频格式进…

idea文件比对

idea文件比对 1.项目内的文件比对2.项目间的文件比对3. 剪切板对比4. 版本历史(不同分支和不同commit)对比 1.项目内的文件比对 在项目中选择好需要比对的文件(类)&#xff0c;然后选择Compare Files Mac下的快捷键是Commandd&#xff0c; 这样的比对像是git冲突解决一样 …

Leetcode41缺失的第一个正数

思路&#xff1a;原地哈希表 长度为N的数组&#xff0c;没有出现过的正整数一定是1~N1中的一个。 此时会思考能不能用一个哈希表来保存出现过的1~N1的数&#xff0c;然后从 1 开始依次枚举正整数&#xff0c;并判断其是否在哈希表中 但是题目要求常数级别的空间&#xff0c;就不…

OpenGL_Learn06(纹理)

接着之前的OpenGL_Learn05&#xff08;纹理&#xff09;-CSDN博客 1. 修改片段着色器 修改片段着色器&#xff0c;仅让笑脸图案朝另一个方向看 >>>>> 纹理坐标的Y轴没有进行改变&#xff0c;需要改变的是X轴的纹理坐标 片段代码改写如下 #version 330 core out…

SpringCloud 微服务全栈体系(十一)

第十章 RabbitMQ 三、SpringAMQP SpringAMQP 是基于 RabbitMQ 封装的一套模板&#xff0c;并且还利用 SpringBoot 对其实现了自动装配&#xff0c;使用起来非常方便。 SpringAmqp 的官方地址&#xff1a;https://spring.io/projects/spring-amqp SpringAMQP 提供了三个功能&…

九、W5100S/W5500+RP2040树莓派Pico<SNTP 获取网络时间>

文章目录 1 前言2 协议简介2.1 什么是SNTP2.2 SNTP的优点2.3 SNTP原理2.4 应用场景 3 WIZnet以太网芯片4 SNTP网络设置示例概述以及使用4.1 流程图4.2 准备工作核心4.3 连接方式4.4 主要代码概述4.5 结果演示 5 注意事项6 相关链接 1 前言 随着科技的不断进步和应用需求的不断变…

el-cascader级联选择器选中一个全选中问题

问题 只选中一个却把同级全选中 解决 :props中添加label、value、children属性 label、value、children属性值需要和后端返回的集合中的字段名保持一致 后端返回数据&#xff1a;

AI:55-基于深度学习的人流量检测

🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌在这个漫长的过程,中途遇到了不少问题,但是…

redis源码分析之IO多路复用

文章目录 1、简述2、多路复用的三个函数3、创建epoll实例4、绑定端口、监听端口5、向epoll实例注册连接事件6、从epoll实例中获取就绪的事件 1、简述 众所周知&#xff0c;redis是一款抗高并发的利器&#xff0c;据官方压测&#xff0c;单机可达10万qps。但背后实际处理命令的…

07、vue : 无法加载文件 C:\Users\JH\AppData\Roaming\npm\vue.ps1,因为在此系统上禁止运行脚本。

目录 问题解决&#xff1a; 问题 vue : 无法加载文件 C:\Users\JH\AppData\Roaming\npm\vue.ps1&#xff0c;因为在此系统上禁止运行脚本。 在使用 VSCode 时&#xff0c;创建 Vue 项目报的错 创建不了 Vue 项目 解决&#xff1a; 因为在此系统上禁止运行该脚本&#xff0…

什么是DITA?从百度的回答说起

▲ 搜索“大龙谈智能内容”关注GongZongHao▲ 什么是DITA? 把这个问题输入百度&#xff0c;获得以下回答&#xff1a; DITA 是“Darwin Information Typing Architecture”&#xff08;达尔文信息类型化体系结构&#xff09;的缩写&#xff0c;它是IBM 公司为OASIS 所支持…

交叉编译程序:以 freetype 为例

1 程序运行的一些基础知识 1.1 编译程序时去哪找头文件&#xff1f; 系统目录&#xff1a;就是交叉编译工具链里的某个 include 目录&#xff1b;也可以自己指定&#xff1a;编译时用 “ -I dir ” 选项指定。 1.2 链接时去哪找库文件&#xff1f; 系统目录&#…

面试算法48:序列化和反序列化二叉树

题目 请设计一个算法将二叉树序列化成一个字符串&#xff0c;并能将该字符串反序列化出原来二叉树的算法。 分析 先考虑如何将二叉树序列化为一个字符串。需要逐个遍历二叉树的每个节点&#xff0c;每遍历到一个节点就将节点的值序列化到字符串中。以前序遍历的顺序遍历二叉…

latex设置图片的位置

Latex提供了一些命令来控制图片的位置。我们可以通过使用\begin{figure}[位置选项]来控制图片的位置。位置选项可以有h、t、b、p、!这五个&#xff0c;分别表示以下含义&#xff1a; h:表示放在当前位置&#xff0c;不过有时由于论文的格式限制&#xff0c;可能放不下。 t:表示…

VulnHub jarbas

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【python】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏…

ps5计时计费管理系统软件怎么使用教学,佳易王PS5体验馆计时收费管理倒计时提醒软件试用下载

ps5计时计费管理系统软件怎么使用教学&#xff0c;佳易王PS5体验馆计时收费管理倒计时提醒软件试用下载 每台机子可以自由设置倒计时提醒的时间&#xff0c;到了时间后&#xff0c;电脑会发出语音提醒同时改变颜色双重提醒方式。也可以在中途关闭提醒或更改提醒时间。每个机子可…

6.Spark共享变量

概述 共享变量 共享变量的工作原理Broadcast VariableAccumulator 共享变量 共享变量的工作原理 通常&#xff0c;当给 Spark 操作的函数(如 mpa 或 reduce) 在 Spark 集群上执行时&#xff0c;函数中的变量单独的拷贝到各个节点上&#xff0c;函数执行时&#xff0c;使用…

Linux应用开发基础知识——交叉编译与gcc编译(一)

前言&#xff1a; 源文件需要经过编译才能生成可执行文件。在 Windows 下进行开发时&#xff0c;只需 要点几个按钮即可编译&#xff0c;集成开发环境(比如 Visual studio)已经将各种编译 工具的使用封装好了。Linux 下也有很优秀的集成开发工具&#xff0c;但是更多的时候是 直…
最新文章