C++中如何获取虚表和虚函数的地址

获取虚函数的地址

虚函数是C++中用于实现多态的一种机制,该机制的原理在此不做赘述。本文主要讨论如何获取虚表以及虚函数的地址

class ClassA {
private:
    int _a;
    double _b;
public:
    ClassA(int a, double b) : _a(a), _b(b) { }
    virtual int funcA(int a) { return a; }
    virtual double funcB() { return _b; }
};

在这里插入图片描述

#include <iostream>

#define PRINT(val) \
    std::cout << #val << ": " << val << std::endl

int main()
{
    ClassA classA(3, 1.2);
    // 虚表指针
    intptr_t* vptr = reinterpret_cast<intptr_t*>(&classA);  
    // 解引用,获取虚表的地址
    intptr_t vtable_addr = *vptr; 
    // 指向第一个虚函数地址
    intptr_t* virtual_func_ptr = reinterpret_cast<intptr_t*>(vtable_addr);
    // 解引用,获取funcA的地址
    intptr_t funcA_addr  = *virtual_func_ptr; 
    // 解引用,获取funcB的地址
    intptr_t funcB_addr  = *(virtual_func_ptr + 1); 
    // funcB的地址
    intptr_t funcB_addr2 = *reinterpret_cast<intptr_t*>(vtable_addr + sizeof(intptr_t)); 

    std::cout << std::hex;
    PRINT(vptr);
    PRINT(vtable_addr);
    PRINT(funcA_addr); 
    PRINT(funcB_addr);
    PRINT(funcB_addr2);

	// 将函数地址转化为对应类型的函数
    typedef int (*FuncAType)(ClassA*, int);
    typedef double (*FuncBType)(ClassA*);
    FuncAType funcA = (FuncAType)funcA_addr;
    FuncBType funcB = (FuncBType)funcB_addr;
    FuncBType funcB2 = (FuncBType)funcB_addr2;

	// 函数调用
    int a = funcA(&classA, 0x21);
    double b = funcB(&classA);
    double b2 = funcB2(&classA);
    
    PRINT(a);
    PRINT(b);
    PRINT(b2);
    PRINT(sizeof(intptr_t));

    return 0;
}

输出结果如下:

vptr: 0x7ffdb035e0d0
vtable_addr: 401288
funcA_addr: 401136
funcB_addr: 401146
funcB_addr2: 401146
a: 21
b: 1.2
b2: 1.2
sizeof(intptr_t): 8
  • vptr:虚表指针,指向虚表,解引用后即可获得虚表的地址值。

  • vtable_addr:虚表地址,存放在vptr所指向的内存中。

  • virtual_func_ptr:将虚表地址vtable_addr强转为指针,指向虚函数地址。

  • funcA_addr:将virtual_func_ptr解引用,即得到第一个虚函数的地址。

  • funcB_addr:将virtual_func_ptr + 1解引用,即得到第二个虚函数的地址。

  • funcB_addr2:将vtable_addr + sizeof(intptr_t),先强转为指向虚函数地址的指针,再解引用,即得到第二个虚函数的地址,对于32位系统sizeof(intptr_t)的值为4,64位系统则等于8。

  • 对于funcB_addr和funcB_addr2的理解

    • 我们可以按照如下方式去理解:

      int* p = new int[4]{1, 2, 3, 4};
      int p0 = *p;       // 第一个元素,很容易理解
      int p1 = *(p + 1); // 第二个元素,很容易理解
      
      // 得到指针p的地址值
      intptr_t addr = reinterpret_cast<intptr_t>(p); 
      
      // 每4个(sizeof(int)为4)字节存放一个元素
      // 所以addr+4*i即表示第i+1个元素的地址。
      int p1_2 = *reinterpret_cast<int*>(addr + sizeof(int)); // 第二个元素的值
      
      PRINT(p0); // 输出1
      PRINT(p1); // 输出2
      PRINT(p1_2); // 输出2
      

      funcB_addr就类似p1,funcB_addr2类似于p1_2,virtual_func_ptr类似于p,vtable_addr类似于addr,虚函数地址即为元素,每个元素占sizeof(intptr_t)个字节。

虚函数在虚表中的偏移值
auto funcA_ptr = &ClassA::funcA;
auto funcB_ptr = &ClassA::funcB;
intptr_t funcA_offset = reinterpret_cast<intptr_t>((intptr_t&)funcA_ptr);
intptr_t funcB_offset = reinterpret_cast<intptr_t>((intptr_t&)funcB_ptr);

PRINT(funcA_offset); // 输出1,实际偏移值为0
PRINT(funcB_offset); // 输出9,实际偏移值为8
  • 可以看出funcA的偏移值是funcA_offset - 1,funcB的偏移值是funcB_offset - 1。

  • 可以通过上述偏移值和虚表指针来确定虚函数的实际地址。而不是通过给定值。

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

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

相关文章

非常好用的组件库【semi.design】

文章目录 前言semi.design是什么&#xff1f;怎么使用&#xff1f;设计稿转代码后言 前言 hello world欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;前端系列文章 &#x1f431;‍&#x1f453;博主在前端领域还有很多知识和技术需要掌握&#xff0c;正在不…

真的设计师做图只需要一个炫云客户端就够了

真的设计师做图只需要一个炫云客户端就够了&#xff0c;为什么这么说呢&#xff1f;因为炫云的这个客户端功能真的太全了&#xff0c;设计师想要的功能在炫云客户端上都有&#xff0c;而且还很多功能是免费的&#xff0c;非常的实用&#xff0c;具体有哪些功能我们一起来看看吧…

从硬件“卷”到UI交互,车企怎样才能掌握智能化「灵魂」

随着汽车智能化为座舱交互带来的超越传统汽车的感知能力和算力&#xff0c;车企在视觉体验设计&#xff08;包括仪表、车机、HUD的UI设计以及HMI相关业务模块&#xff0c;比如智驾视觉交互&#xff09;的布局&#xff0c;正在进入新周期。 与此同时&#xff0c;交互逻辑和UI设计…

【苍穹外卖 | 项目日记】第九天 万字总结

前言&#xff1a; 之前就写完了&#xff0c;用了几天补一下项目总结&#xff0c;本文会从宏观上介绍整体项目构架和所应用的技术以及项目亮点&#xff0c;最后再加上我个人的感悟。本文适合打算开始写苍穹外卖的小伙伴阅读&#xff0c;提高对整体项目的认知。 往期项目日记&am…

黑客技术-小白自学

前言 一、什么是网络安全 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 无论网络、Web、移动、桌面、云等哪个领域&#xff0c;都有攻与防…

网格变形算法

网格变形 需求分析技术分析 需求分析 根据几何模型上的几个特征点&#xff0c;对几何模型进行变形。比如 技术分析 把几何模型使用三角面片表示&#xff0c;然后通过网格映射变形进行实现。关于网格这块有本经典的书可以参考&#xff0c;《ploygon mesh processing》。上面…

Android---App 崩溃

崩溃问题是衡量 App 质量的决定性考核标准。Android 系统会输出各种相应的 log 日志&#xff0c;很大程度上降低了工程师 debug 崩溃问题的难度。如果要给 crash 日志进行分类&#xff0c;可以分为2大类&#xff1a;JVM 异常&#xff08;Exception&#xff09;堆栈信息和 nativ…

Linux内核密码模块

目录 密码算法介绍 Hash摘要算法 Cipher加解密算法 块密码算法 认证算法 MAC和HMAC AEAD算法 Linux内核密码模块的基本构件 Linux内核密码模块介绍 如何使用Linux密码模块 用户层调用Linux内核密码模块的方法 cryptodev AF_ALG 如何开发一个密码引擎驱动 开发一个…

数据的备份和恢复

数据的备份和恢复 备份&#xff1a;完全备份 增量备份 完全备份&#xff1a;将整个数据库完整的进行备份 增量备份&#xff1a;在完全备份的基础之上&#xff0c;对后续新增的内容进行备份 备份的需求 1、在生产环境中&#xff0c;数据的安全至关重要、任何数据的丢失都可…

【MySQL进阶之路丨第十六篇】一文带你精通MySQL函数

引言 在上一篇中我们介绍了MySQL数据的导入与导出&#xff1b;在开发中&#xff0c;对MySQL函数的运用是十分重要的。这一篇我们使用命令行方式来帮助读者掌握MySQL中函数的操作。 上一篇链接&#xff1a;【MySQL进阶之路丨第十五篇】一文带你精通MySQL数据的导入与导出 MySQ…

vue3使用element plus时遇到的问题

1.el-form中input无法输入 问题描述&#xff1a;在el-form中的el-input中输入数字或字母时出现卡顿&#xff0c;输入不进去的现象 问题原因&#xff1a;el-form的ref和model的名称写成了一样的单词 问题解决&#xff1a;两个不能一样 2.input去除边框 问题描述&#xff1a;…

2、鸿蒙开发工具首次运行时开发环境配置

请务必在第一次运行时配置好开发环境&#xff0c;如果取消了配置&#xff0c;后续再配置会比较麻烦 1、点击工具图标运行 2、在欢迎页中点击“Agree” 3、默认“Do not import setting”&#xff0c;点击“OK” 3、此片设置Nodejs和Ohpm的安装&#xff0c;其中&#xff0c; …

基于springboot实现高校党务平台管理系统【项目源码】

基于springboot实现高校党务平台管理系统演示 Java技术 Java是由Sun公司推出的一门跨平台的面向对象的程序设计语言。因为Java 技术具有卓越的通用性、高效性、健壮的安全性和平台移植性的特点&#xff0c;而且Java是开源的&#xff0c;拥有全世界最大的开发者专业社群&#x…

Python类的定义和使用:什么是类?实在不知道啥叫累!

文章目录 前言1.基础概念2.定义一个 Person 类3.类定义4.类方法定义5.类的继承6.类的公有,私有7.子类调用父类的方法关于Python技术储备一、Python所有方向的学习路线二、Python基础学习视频三、精品Python学习书籍四、Python工具包项目源码合集①Python工具包②Python实战案例…

【紫光同创国产FPGA教程】——【PGL22G第十一章】以太网传输实验例程

本原创教程由深圳市小眼睛科技有限公司创作&#xff0c;版权归本公司所有&#xff0c;如需转载&#xff0c;需授权并注www.meyesemi.com) 适用于板卡型号&#xff1a; 紫光同创PGL22G开发平台&#xff08;盘古22K&#xff09; 一&#xff1a;盘古22K开发板&#xff08;紫光…

VEX —— Intrinsic attribute

目录 查看 使用 PackedGeometry Intrinsic attribute 内在属性是已经被计算的值&#xff08;从几何体派生出来的&#xff09;&#xff0c;可像属性一样访问&#xff1b; 查看 ginfo -I&#xff0c;打印所有内在属性&#xff1b;geometry spreadsheet&#xff0c;查看内在属性…

08.Diffusion Model数学原理分析(下)

文章目录 denoising matching term σ t z \sigma_tz σt​z的猜想Diffusion Model for SpeechDiffusion Model for TextMask-Predict 部分截图来自原课程视频《2023李宏毅最新生成式AI教程》&#xff0c;B站自行搜索。 书接上文。 denoising matching term E q ( x t ∣ x 0 …

第四章:人工智能深度学习教程-激活函数(第一节-激活函数)

简单来说&#xff0c;人工神经元计算其输入的“加权和”并添加偏差&#xff0c;如下图所示的净输入。 从数学上来说&#xff0c; 现在净输入的值可以是从 -inf 到 inf 之间的任何值。神经元并不真正知道如何绑定到值&#xff0c;因此无法决定激发模式。因此激活函数是人工神经网…

【Proteus仿真】【STM32单片机】汽车尾灯控制设计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真STM32单片机控制器&#xff0c;使用按键、LED模块等。 主要功能&#xff1a; 系统运行后&#xff0c;系统运行后&#xff0c;系统开始运行&#xff0c;K1键控制左转向灯&#xff…

【PHP函数封装】分分钟帮你实现数据脱敏处理, 支持手机号码、邮箱、身份证号 中文字符串!

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;web开发者、设计师、技术分享博主 &#x1f40b; 希望大家多多支持一下, 我们一起进步&#xff01;&#x1f604; &#x1f3c5; 如果文章对你有帮助的话&#xff0c;欢迎评论 &#x1f4ac;点赞&#x1…
最新文章