如果一个类有虚函数,那么这个类的虚函数会被放在一个虚函数表里面, 使用这个类声明的对象中,会有一个指向虚函数表的指针,当使用指向 这个对象的指针或者这个对象的引用调用一个虚函数的时候,就会从虚函数表中去 查找该函数,然后对其进行调用。

如果有如下的类:

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++对象模型》调用虚函数相关推荐

  1. C++对象模型3——vptr的位置、手动调用虚函数、从汇编代码看普通调用和多态调用

    一.vptr的位置 class test { public:int i; virtual void testfunc() {} };int main() {test a;char* p1 = rein ...

  2. 深度探索C++ 对象模型(7)-Data member的布局(虚继承)

    虚拟继承 namespace ObjectMultiDerived {class Point2d {public:// has virtual functionsvirtual void print( ...

  3. 《深度探索C++对象模型》--5 构造析构拷贝 6 执行期语意学

     <深度探索C++对象模型>--5构造.析构.拷贝语意学 1.纯虚函数: (1)C++可以定义和调用一个纯虚函数,不过只可以静态调用,不可以由虚拟机制调用. 注意:pure virtu ...

  4. 深度探索C++ 对象模型(3)-默认构造函数Default Constructor

    1. Default Constructor只对base class subobjects和member class objects初始化,对data member不做操作 2. 编译器构造Defau ...

  5. 深度探索C++对象模型第2章 构造函数语义学

    默认构造函数 两个误区: 1 任何class如果没有定义默认构造函数,就会被合成一个出来:只有在某些情况下被合成 2 编译器合成出来的默认构造函数会明确设定class中每一个数据成员的默认值 :默认值 ...

  6. 《深度探索C++对象模型》读书笔记第五章:构造析构拷贝语意学

    <深度探索C++对象模型>读书笔记第五章:构造析构拷贝语意学 对于abstract base class(抽象基类),class中的data member应该被初始化,并且只在constr ...

  7. [读书笔记]《深度探索C++对象模型》

    文章目录 前言 思维导图 第一章 关于对象 第二章 构造函数语意学 构造函数 拷贝构造函数 初始化列表 第三章 Data 语意学 第四章 Function 语意学 非静态成员函数 静态成员函数 虚成员 ...

  8. 深度探索C++ 对象模型(7)-Data member的布局(无继承、继承无多态、继承多态、多层继承)

    无继承 继承无多态 继承多态 虚表 : 用来存放基类的每一个虚函数,再加上首位的一个slots(支持RTTI). 每个class object导入一个vptr,提供执行期的链接,使得每一个class ...

  9. 深度探索C++ 对象模型(4)-Default Copy Constructor(3)

    程序转化语意学 1. 显式初始化 原代码为: X x0; void foo_bar() { X x1(x0);X x2 = x0; X x3 = X(x0);} 编译器将产生拷贝构造函数,调用拷贝构造 ...

  10. 深度探索C++ 对象模型(3)-默认构造函数Default Constructor续

    (1)带有虚函数的类 class Widget { public: virtual int flip() = 0;//..}; void flip(const Widget* widget ) { w ...

最新文章

  1. python 基础学习 正则表达式1(规则)
  2. 关于jsb中js与c++的相互调用
  3. 原生js增加或者删除class
  4. 驱动备份工具哪个好_大庆seo排名优化推广公司工具哪个好
  5. dma和通道的区别_STM32 定时器触发 ADC 多通道采集,DMA搬运至内存
  6. 闲来无事,仿了一个百度杀毒主界面
  7. ROS机器人程序设计(原书第2版)3.1.2 ROS节点启动时调用gdb调试器
  8. 采集网页数据生成到静态模板newslist.html文件中(正则表达式)
  9. 【谷歌浏览器】扫码登录不上解决方案
  10. [RK3566] 通过GM8775 点LVDS屏调试记录
  11. wget:Unable to establish SSL connection错误
  12. 腾讯研究院发布《2021数字科技前沿应用趋势》
  13. 授权公众号第三方平台和开发者模式冲突吗?
  14. __new__方法,单例模式的小应用
  15. 微型计算机的英文术语,计算机常见英语词汇解释
  16. [论文阅读]DynaSLAM II: Tightly-Coupled Multi-Object Tracking and SLAM
  17. HikariCP 整合spring
  18. [渝粤教育] 天津科技大学 化工开发与创新实验 参考 资料
  19. javascript 0基础入门
  20. dz论坛附件在服务器中的位置,discuz x3 如何将头像和帖内等附件分离到远程服务器?...

热门文章

  1. uiswitchbutton 点击不改变状态_ES6专题—Generator与react状态机(14)
  2. Golang实践录:生成版本号和编译时间
  3. 计算时间差_小王子是怎么用四步法进行时间计算并成功避开日界线的
  4. 95-910-144-源码-FlinkSQL-Flink的UDF
  5. 【Elasticsearch】Elasticsearch底层系列之Shard Allocation机制
  6. 【Elasticsearch】bulk default_local reports failures when export documents
  7. 【Kafka】Kafka eagle 监控界面无数据
  8. 【Kafka】Kafka Schema Registry 原理
  9. 【MySQL】mysql The server time zone value “乱码” 错误
  10. 【Flink】Flink的窗口触发器 PurgingTrigger