《深度探索C++对象模型》调用虚函数
如果一个类有虚函数,那么这个类的虚函数会被放在一个虚函数表里面, 使用这个类声明的对象中,会有一个指向虚函数表的指针,当使用指向 这个对象的指针或者这个对象的引用调用一个虚函数的时候,就会从虚函数表中去 查找该函数,然后对其进行调用。
如果有如下的类:
class A {public :int m_a;A() {}~A() {}virtual void test() { cout << "A info : " << __LINE__ << " , " << __func__ << endl;} };class B : public A{public :int m_b;B() {}~B() {}virtual void test() { cout << "B info : " << __LINE__ << " , " << __func__ << endl;} };
那么我们显示出一个 B 类对象的内存状态, 这个类声明的对象的内存布局会是下面这样:
#ifdef __x86_64__ cout << "__x86_64__" << endl; #else cout << "not 64" << endl; #endifcout << "sizeof(B) = " << sizeof(B) << endl; cout << "sizeof(int) = " << sizeof(int) << endl;B b; b.m_a = 0x01010101; b.m_b = 0x02020202;show_mem(&b, sizeof(b));
执行结果:
__x86_64__ sizeof(B) = 16 sizeof(int) = 4 addrress : 00 f8 cc fa ff 7f 00 00 memory layout : 00 0f 40 00 00 00 00 00 01 01 01 01 02 02 02 02
我们看到,拥有两个 int 成员变量的 b 对象,它占用的内存大小却不是 两个 sizeof(int) 的和 8,而是16。很明显,另外8个字节就是存放虚函数表地址 的了,因为目前使用的是64位系统,指针占用的空间是64 bit。
那么,我们现在知道了一个对象的内存布局后,就可以采取 "非法" 手段 调用一个虚函数了。比如下面这段代码:
#ifdef __x86_64__ typedef unsigned long int POINT_SIZE; #else typedef int POINT_SIZE; #endiftypedef void(*Fun)();//获取对象的地址 POINT_SIZE *po = (POINT_SIZE *)&b;//获取这个对象前 8 个字节的值,这个值是虚函数表的地址 POINT_SIZE tbl = po[0];//把这个值转换为地址类型,也就是虚函数表的地址 POINT_SIZE *ptbl = (POINT_SIZE *)tbl;int pos = 0; //虚函数表的第一表项就是第一个虚函数的函数地址, //这里将其转换为函数类型 Fun pfun = (Fun)(ptbl[pos]);//调用这个函数 pfun();
调用的结果是:
B info : 38 , test
说明调用了 B 类的虚函数,内存布局如下:
这样,我们使用非常规手段就可以调用一个类的虚函数了。
同步发表:http://www.fengbohello.top/book/b/1275
转载于:https://www.cnblogs.com/fengbohello/p/6261873.html
《深度探索C++对象模型》调用虚函数相关推荐
- C++对象模型3——vptr的位置、手动调用虚函数、从汇编代码看普通调用和多态调用
一.vptr的位置 class test { public:int i; virtual void testfunc() {} };int main() {test a;char* p1 = rein ...
- 深度探索C++ 对象模型(7)-Data member的布局(虚继承)
虚拟继承 namespace ObjectMultiDerived {class Point2d {public:// has virtual functionsvirtual void print( ...
- 《深度探索C++对象模型》--5 构造析构拷贝 6 执行期语意学
<深度探索C++对象模型>--5构造.析构.拷贝语意学 1.纯虚函数: (1)C++可以定义和调用一个纯虚函数,不过只可以静态调用,不可以由虚拟机制调用. 注意:pure virtu ...
- 深度探索C++ 对象模型(3)-默认构造函数Default Constructor
1. Default Constructor只对base class subobjects和member class objects初始化,对data member不做操作 2. 编译器构造Defau ...
- 深度探索C++对象模型第2章 构造函数语义学
默认构造函数 两个误区: 1 任何class如果没有定义默认构造函数,就会被合成一个出来:只有在某些情况下被合成 2 编译器合成出来的默认构造函数会明确设定class中每一个数据成员的默认值 :默认值 ...
- 《深度探索C++对象模型》读书笔记第五章:构造析构拷贝语意学
<深度探索C++对象模型>读书笔记第五章:构造析构拷贝语意学 对于abstract base class(抽象基类),class中的data member应该被初始化,并且只在constr ...
- [读书笔记]《深度探索C++对象模型》
文章目录 前言 思维导图 第一章 关于对象 第二章 构造函数语意学 构造函数 拷贝构造函数 初始化列表 第三章 Data 语意学 第四章 Function 语意学 非静态成员函数 静态成员函数 虚成员 ...
- 深度探索C++ 对象模型(7)-Data member的布局(无继承、继承无多态、继承多态、多层继承)
无继承 继承无多态 继承多态 虚表 : 用来存放基类的每一个虚函数,再加上首位的一个slots(支持RTTI). 每个class object导入一个vptr,提供执行期的链接,使得每一个class ...
- 深度探索C++ 对象模型(4)-Default Copy Constructor(3)
程序转化语意学 1. 显式初始化 原代码为: X x0; void foo_bar() { X x1(x0);X x2 = x0; X x3 = X(x0);} 编译器将产生拷贝构造函数,调用拷贝构造 ...
- 深度探索C++ 对象模型(3)-默认构造函数Default Constructor续
(1)带有虚函数的类 class Widget { public: virtual int flip() = 0;//..}; void flip(const Widget* widget ) { w ...
最新文章
- python 基础学习 正则表达式1(规则)
- 关于jsb中js与c++的相互调用
- 原生js增加或者删除class
- 驱动备份工具哪个好_大庆seo排名优化推广公司工具哪个好
- dma和通道的区别_STM32 定时器触发 ADC 多通道采集,DMA搬运至内存
- 闲来无事,仿了一个百度杀毒主界面
- ROS机器人程序设计(原书第2版)3.1.2 ROS节点启动时调用gdb调试器
- 采集网页数据生成到静态模板newslist.html文件中(正则表达式)
- 【谷歌浏览器】扫码登录不上解决方案
- [RK3566] 通过GM8775 点LVDS屏调试记录
- wget:Unable to establish SSL connection错误
- 腾讯研究院发布《2021数字科技前沿应用趋势》
- 授权公众号第三方平台和开发者模式冲突吗?
- __new__方法,单例模式的小应用
- 微型计算机的英文术语,计算机常见英语词汇解释
- [论文阅读]DynaSLAM II: Tightly-Coupled Multi-Object Tracking and SLAM
- HikariCP 整合spring
- [渝粤教育] 天津科技大学 化工开发与创新实验 参考 资料
- javascript 0基础入门
- dz论坛附件在服务器中的位置,discuz x3 如何将头像和帖内等附件分离到远程服务器?...
热门文章
- uiswitchbutton 点击不改变状态_ES6专题—Generator与react状态机(14)
- Golang实践录:生成版本号和编译时间
- 计算时间差_小王子是怎么用四步法进行时间计算并成功避开日界线的
- 95-910-144-源码-FlinkSQL-Flink的UDF
- 【Elasticsearch】Elasticsearch底层系列之Shard Allocation机制
- 【Elasticsearch】bulk default_local reports failures when export documents
- 【Kafka】Kafka eagle 监控界面无数据
- 【Kafka】Kafka Schema Registry 原理
- 【MySQL】mysql The server time zone value “乱码” 错误
- 【Flink】Flink的窗口触发器 PurgingTrigger