C++_虚函数表

虚函数表

  • 介绍
  • 源码
  • 运行结果
    • 笔记扩充
    • 函数名联编
    • 静态联编
    • 动态联编

介绍

1.编译器通过指针或引用调用虚函数,不会立即生成函数调用指令,而是用 二级函数指针 代替

1.1确定真实类型
1.2找到虚函数表从而找到入口地址
1.3根据入口地址调用函数(PS:俗称 函数指针)

** 虚函数表 内部存储格式展示**
在这里插入图片描述
代码图详解
在这里插入图片描述

源码

#include<iostream>
#include<string>
using namespace std;class N
{
public:void foo(){cout << "N::foo" << endl;}void ber(){cout << "N::ber" << endl;}int m_a;int m_b;
};
class A
{
public:virtual void foo(){cout << "A::foo" << endl;}virtual void ber(){cout << "A::ber" << endl;}double m_a;int m_b;
};
class B:public A
{
public:void foo(){cout << "B::foo" << endl;}void ber(){cout << "B::ber" << endl;}
};
void main()
{A a;//在A类型中会多生成一个最大类型的 字节指针(内部存储的是函数指针)B b;//在B类型中会多生成一个最大类型的 字节指针(内部存储的是函数指针)A*pa = &b;//获取 N 类型大小cout << "sizeof(N):" << sizeof(N);//获取 N 相对于 m_a 的距离cout << ",m_a:" << offsetof(N, m_a);//获取 N 相对于 m_b 的距离cout << ",m_b:" << offsetof(N, m_b) << endl;//获取 A 类型大小cout << "sizeof(N):" << sizeof(A);//获取 A 相对于 m_a 的距离cout << ",m_a:" << offsetof(A, m_a);//获取 A 相对于 m_b 的距离cout << ",m_b:" << offsetof(A, m_b) << endl;cout << "-------------------分隔符-------------------" << endl;
//函数指针调用函数void *vf_ptr = *(void**)&a; //获取 A类型 中 a 地址cout <<"A类型 中 a 地址为:"<< vf_ptr << endl;    //打印 A类型 中 a 地址cout << "-------------------分隔符-------------------" << endl;//取别名typedef void(*VFUN)(void*); //VFUN 相当于 void(*)  // *VFUN 函数指针类型typedef VFUN* VPTR;         //VPTR 相当于 void(**) //指向函数指针类型的指针 VPTR虚函数表类型VPTR _vfptr = *(VPTR*)&a;   //获取 A类型 中 a 地址cout << "A类型 中 a 地址为:" << _vfptr << endl;   //打印 A类型 中 a 地址a.foo();                    //正常调用方法_vfptr[0](&a);              //编译器中调用方法 结果为:A::foo_vfptr[1](&a);              //编译器中调用方法 结果为:A::bercout << "-------------------分隔符-------------------" << endl;VPTR _vfptr1 = *(VPTR*)&b;   //获取 B类型 中 b 地址cout << "B类型 中 b 地址为:" << _vfptr1 << endl;   //打印 B类型 中 b 地址b.foo();                    //正常调用方法_vfptr1[0](&b);              //编译器中调用方法 结果为:B::foo_vfptr1[1](&b);              //编译器中调用方法 结果为:B::bersystem("pause");
}

运行结果

sizeof(N):8,m_a:0,m_b:4
sizeof(N):24,m_a:8,m_b:16
-------------------分隔符-------------------
A类型 中 a 地址为:0015DC80
-------------------分隔符-------------------
A类型 中 a 地址为:0015DC80
A::foo
A::foo
A::ber
-------------------分隔符-------------------
B类型 中 b 地址为:0015DCA0
B::foo
B::foo
B::ber
请按任意键继续. . .

笔记扩充

void(VFUN)(void) 的代码解释,参考下列源码

#include<iostream>
#include<string>
using namespace std;//构造3个通用函数
void TEST1(void) { printf("test1\n"); }//函数定义  
void TEST2(void) { printf("test2\n"); }//函数定义  
void TEST3(void) { printf("test3\n"); }//函数定义  
//声明(取别名为:(*func)函数)是 void 类型
typedef void(*func)(void);void test(int i)
{func vTask[3] = { &TEST1, &TEST2, &TEST3 };//func 类型代替 void功能func fun = vTask[i];//将vTask函数赋值到fun中(*fun)();//调用(*fun) ()函数
}
void main()
{test(0);test(1);test(2);system("pause");
}

函数名联编

将源代码中的函数调用解释为执行特定的函数代码块被称为 函数名联编

静态联编

1.静态联编是指 联编工作在编译阶段完成的,这种联编过程是在程序运行之前完成的, 又称为:早期联编
2.静态联编对函数的选择是基于指向对象的指针或者引用的类型
3.优点是效率高,灵活性差
4.静态联编是根据 所定义的类 来调用 类中函数(PS:相当于直接调用当前类代码,不会做任何检查)

动态联编

1.动态联编 是指联编在程序运行时动态地进行,这种联编又称为晚期联编。或动态束定
2.动态联编对成员函数的选择是基于对象的类型
3.优点是灵活性强,效率低
4.实际上是在运行时虚函数(virtual)的实现。(PS:先进行检查后,根据当时的情况来确定调用哪个同名函数)
动态联编 调用步骤:

1.1确定真实类型
1.2找到虚函数表从而找到入口地址
1.3根据入口地址调用函数(PS:俗称 函数指针)

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

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

相关文章

RT-Thread入门笔记3-线程的创建

线程 RT-Thread 中&#xff0c;线程由三部分组成&#xff1a;线程代码&#xff08;入口函数&#xff09;、线程控制块、线程堆栈. 线程代码: 线程控制块 : 线程控制块是操作系统用于管理线程的一个数据结构&#xff0c; 它会存放线程的一些信息&#xff0c; 例如优先级、 线程…

使用Notepad++将多行数据合并成一行

步骤 1、按CtrlF&#xff0c;弹出“替换”的窗口&#xff1b; 2、选择“替换”菜单&#xff1b; 3、“查找目标”内容输入为&#xff1a;\r\n&#xff1b; 4、“替换为”内容为空&#xff1b; 5、“查找模式”选择为正则表达式&#xff1b; 6、设置好之后&#xff0c;点击“全…

Vue3 父事件覆盖子事件,Vue2 的 v-on=“$listeners“ 的替代方案

在 Vue3 中&#xff0c;$listeners 被删除 子组件代码&#xff0c;需要特别注意的是事件名为 on 开头&#xff0c;例如 onBack。不确定的可以通过给父组件传递 事件或属性&#xff0c;再打印子组件的 attrs useAttrs()&#xff0c;来确定传值 // template v-bind"newA…

了解PyTorch中的缩放点积注意力及演示

torch.nn.functional.scaled_dot_product_attention 函数在 PyTorch 框架中用于实现缩放点积注意力&#xff08;Scaled Dot-Product Attention&#xff09;。这是一种在自然语言处理和计算机视觉等领域常用的注意力机制。它的主要目的是通过计算查询&#xff08;query&#xff…

Linux ----冯诺依曼体系结构与操作系统

目录 前言 一、冯诺依曼体系结构 二、为什么选择冯诺依曼体系结构&#xff1f; 三、使用冯诺依曼结构解释问题 问题1&#xff1a; 问题2: 四、操作系统 1.操作系统是什么 2.为什么需要操作系统 3.操作系统怎样管理的 4.如何给用户提供良好环境 五、我们是怎样调用系…

Github 2024-01-12Java开源项目日报 Top10

根据Github Trendings的统计&#xff0c;今日(2024-01-12统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量Java项目10Vue项目3 Apache Flink: 开源流处理框架 创建周期&#xff1a;3506 天开发语言&#xff1a;Java协…

iOS rootless无根越狱解决方案

据游戏工委数据统计&#xff0c;2023年国内游戏市场实际销售收入与用户规模双双创下新高&#xff0c;游戏普遍采用多端并发方式&#xff0c;成为收入增长的主因之一。 中国市场实际销售收入及增长率丨数据来源&#xff1a;游戏工委 多端互通既是机遇&#xff0c;也是挑战。从游…

【AI大模型应用开发】1.0 Prompt Engineering(提示词工程)- 典型构成、原则与技巧,代码中加入Prompt

从这篇文章开始&#xff0c;我们就正式开始学习AI大模型应用开发的相关知识了。首先是提示词工程&#xff08;Prompt Engineering&#xff09;。 文章目录 0. 什么是提示词&#xff08;Prompt&#xff09;1. 为什么Prompt会起作用 - 大模型工作原理2. Prompt的典型构成、原则与…

【5】商密测评密码辅助工具

0X01 前言 最近在学了下商密测评&#xff0c;研究了下技术层面的测评&#xff0c;感觉找工具不方便&#xff0c;就顺手自己造了个辅助工具&#xff0c;都是自己遇到需要用的。 0x02 工具功能介绍 不爱打字&#xff0c;直接上图。后续根据技术测评层面需要继续完善和增加功能。…

基于VSG控制的MMC并网逆变器MATLAB仿真模型

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 模型简介 根据传统同步发电机的运行特性设计了MMC-VSG功频控制器和励磁控制器&#xff0c; 实现了MMC-VSG逆变器对高压电网电压和频率的支撑。该模型包含MMC变流器模块&#xff0c;环流抑制模块&#xff0c;…

HackTheBox-Keeper

OpenVPN连接 连接上HackTheBox&#xff01; 同时找到这个靶机&#xff0c;进行join&#xff01;分配的靶机的地址位10.10.11.227&#xff01; 信息收集 nmap -sT --min-rate 10000 -p- 10.10.11.227 开放端口为22和80端口 服务版本和操作系统信息探测&#xff1a; nmap -s…

Milvus Cloud与携程的向量探索大公开

【User Tech】2024 我们来啦&#xff01; 今年&#xff0c;【User Tech】将更加专注于为社区用户提供技术功能解读、热点答疑&#xff0c;聚焦更丰富、更多样化的行业或使用场景的用户案例。我们期待通过分享更多关于 Milvus Cloud 的实战经验&#xff0c;为大家在 AI、大模型、…

YOLOv8算法改进【NO.98】改进损失函数为最新提出的Shape-IoU

前 言 YOLO算法改进系列出到这&#xff0c;很多朋友问改进如何选择是最佳的&#xff0c;下面我就根据个人多年的写作发文章以及指导发文章的经验来看&#xff0c;按照优先顺序进行排序讲解YOLO算法改进方法的顺序选择。具体有需求的同学可以私信我沟通&#xff1a; 第一…

李沐之经典卷积神经网络

目录 1. LeNet 2. 代码实现 1. LeNet 输入是32*32图片&#xff0c;放到一个5*5的卷积层里面&#xff0c;卷积层的输出通道数是6&#xff0c;高宽都是28&#xff08;32-5128&#xff09;。再经过2*2的池化层&#xff0c;把28*28变成14*14&#xff08;28-22&#xff09;/214&am…

《Vue2 进阶知识》动态挂载组件之Vue.extend + vm.$mount

前言 目前工作还是以 Vue2 为主&#xff0c;今早有人提问 如何动态挂载组件&#xff1f; 话说很久很久以前就实现过&#xff0c;今天再详细的整理一下此问题&#xff01; 开始 动态组件如下&#xff0c;是个简单的例子&#xff1a; 但请注意这里给了个 id"test2"…

vue 组件 import make sure to provide the “name“ option.

百度了好多结果&#xff0c;都过时了&#xff0c;例如&#xff1a; 模块引入是否加{} 再比如&#xff1a; 对于递归组件&#xff0c;请确保提供“name”选项。 出现该错误情况之一&#xff1a; 错误由未正确引入组件或子组件引起&#xff0c;如element-ui中form表单组件未引…

PostgreSQL之SEMI-JOIN半连接

什么是Semi-Join半连接 Semi-Join半连接&#xff0c;当外表在内表中找到匹配的记录之后&#xff0c;Semi-Join会返回外表中的记录。但即使在内表中找到多条匹配的记录&#xff0c;外表也只会返回已经存在于外表中的记录。而对于子查询&#xff0c;外表的每个符合条件的元组都要…

GitLab 502 Whoops, GitLab is taking too much time to respond. 解决

1、先通过gitlab-ctl restart进行重启&#xff0c;2分钟后看是否可以正常访问&#xff0c;为什么要2分钟&#xff0c;因为gitlab启动会有很多配套的服务启动&#xff0c;包括postgresql等 2、如果上面不行&#xff0c;再看gitlab日志&#xff0c;通过gitlab-ctl tail命令查看&…

【Arduino】编程语言:定时函数、数学函数、字符函数(功能、语法格式、参数说明、返回值) | 软件开发环境:安装步骤介绍(EXE安装版、ZIP安装版)

你的负担将变成礼物,你受的苦将照亮你的路。———泰戈尔 🎯作者主页: 追光者♂🔥 🌸个人简介: 💖[1] 计算机专业硕士研究生💖 🌿[2] 2023年城市之星领跑者TOP1(哈尔滨)🌿 🌟[3] 2022年度博客之星人工智能领域TOP4🌟 🏅[4] 阿里云社区…

再发一波微信红包封面,免费!免费!免费!

我是90后程序员&#xff0c;大家都叫我小码哥&#xff0c;从事互联网近10余年了&#xff0c;一直想在互联网上分享自己的管理经验和技术经验&#xff0c;同时也想找一些志同道合的朋友&#xff0c;一起聊聊如何从互联网中快速的成长起来&#xff0c;无论是通过技术、互联网风口…