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

如果有如下的类:

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;
#endif cout << "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) =
sizeof(int) =
addrress : f8 cc fa ff 7f
memory layout : 0f

我们看到,拥有两个 int 成员变量的 b 对象,它占用的内存大小却不是 两个 sizeof(int) 的和 8,而是16。很明显,另外8个字节就是存放虚函数表地址 的了,因为目前使用的是64位系统,指针占用的空间是64 bit。

那么,我们现在知道了一个对象的内存布局后,就可以采取 "非法" 手段 调用一个虚函数了。比如下面这段代码:

#ifdef __x86_64__
typedef unsigned long int POINT_SIZE;
#else
typedef int POINT_SIZE;
#endif typedef void(*Fun)(); //获取对象的地址
POINT_SIZE *po = (POINT_SIZE *)&b; //获取这个对象前 8 个字节的值,这个值是虚函数表的地址
POINT_SIZE tbl = po[]; //把这个值转换为地址类型,也就是虚函数表的地址
POINT_SIZE *ptbl = (POINT_SIZE *)tbl; int pos = ;
//虚函数表的第一表项就是第一个虚函数的函数地址,
//这里将其转换为函数类型
Fun pfun = (Fun)(ptbl[pos]); //调用这个函数
pfun();

调用的结果是:

B info :  , test

说明调用了 B 类的虚函数,内存布局如下:

这样,我们使用非常规手段就可以调用一个类的虚函数了。


同步发表:http://www.fengbohello.top/book/b/1275

《深度探索C++对象模型》调用虚函数的更多相关文章

  1. [读书系列] 深度探索C++对象模型 初读

    2012年底-2014年初这段时间主要用C++做手游开发,时隔3年,重新拿起<深度探索C++对象模型>这本书,感觉生疏了很多,如果按前阵子的生疏度来说,现在不借助Visual Studio ...

  2. 深度探索C++对象模型

    深度探索C++对象模型 什么是C++对象模型: 语言中直接支持面向对象程序设计的部分. 对于各个支持的底层实现机制. 抽象性与实际性之间找出平衡点, 需要知识, 经验以及许多思考. 导读 这本书是C+ ...

  3. c++学习书籍推荐《深度探索C++对象模型》下载

    百度云及其他网盘下载地址:点我 百度云及其他网盘下载地址:点我 编辑推荐 如果你是一位C++程序员,渴望对于底层知识获得一个完整的了解,那么这本<深度探索C++对象模型>正适合你 作者简介 ...

  4. 《深度探索C++对象模型》读书笔记(一)

    前言 今年中下旬就要找工作了,我计划从现在就开始准备一些面试中会问到的基础知识,包括C++.操作系统.计算机网络.算法和数据结构等.C++就先从这本<深度探索C++对象模型>开始.不同于& ...

  5. 读书笔记《深度探索c++对象模型》 概述

    <深度探索c++对象模型>这本书是我工作一段时间后想更深入了解C++的底层实现知识,如内存布局.模型.内存大小.继承.虚函数表等而阅读的:此外在很多面试或者工作中,对底层的知识的足够了解也 ...

  6. 拾遗与填坑《深度探索C++对象模型》3.3节

    <深度探索C++对象模型>是一本好书,该书作者也是<C++ Primer>的作者,一位绝对的C++大师.诚然该书中也有多多少少的错误一直为人所诟病,但这仍然不妨碍称其为一本好书 ...

  7. 拾遗与填坑《深度探索C++对象模型》3.2节

    <深度探索C++对象模型>是一本好书,该书作者也是<C++ Primer>的作者,一位绝对的C++大师.诚然该书中也有多多少少的错误一直为人所诟病,但这仍然不妨碍称其为一本好书 ...

  8. 【C++】深度探索C++对象模型读书笔记--Data语意学(The Semantics of data)

    1. 一个空类的大小是1 byte.这是为了让这一类的两个对象得以在内存中配置独一无二的地址. 2. Nonstatic data member 放置的是“个别的class object”感兴趣的数据 ...

  9. C++中构造函数能调用虚函数吗?(答案是语法可以,输出错误),但Java里居然可以

    环境:XPSP3 VS2005 今天黑总给应聘者出了一个在C++的构造函数中调用虚函数的问题,具体的题目要比标题复杂,大体情况可以看如下的代码: class Base { public: Base() ...

  10. EC笔记,第二部分:9.不在构造、析构函数中调用虚函数

    9.不在构造.析构函数中调用虚函数 1.在构造函数和析构函数中调用虚函数会产生什么结果呢? #; } 上述程序会产生什么样的输出呢? 你一定会以为会输出: cls2 make cls2 delete ...

随机推荐

  1. 整合django和bootstrap框架

    环境: python版本:2.7.8 django版本:1.7.1 bootstrap版本:3.3.0 首先github上面有两个开源的项目用来整合django和bootstrap. https:// ...

  2. Mysql数据库报错:Cannot add or update a child row: a foreign key constraint fails(添加多对多关系)

    #创建班级表 class Classes(models.Model): title = models.CharField(max_length=32) n=models.ManyToManyField ...

  3. Python常用模块--re

    Python内部的re--传闻中的正则模块,是无数初学者心中的噩梦,几乎到了谈正则色变的地步. 1.正则是干什么的 正则表达式,又称规则表达式.(英语:Regular Expression,在代码中常 ...

  4. SpringMVC框架01——使用IDEA搭建SpringMVC环境

    1.Spring MVC 入门 1.1.Spring MVC 简介 把Web应用程序分为三层,分别是: 控制器(Controller):负责接收并处理请求,响应客户端: 模型(Model):模型数据, ...

  5. 服务端线程模型-NIO服务模型

    上接<服务端线程模型-线程池服务模型>(https://www.cnblogs.com/fudashi233/p/10549221.html). 这篇分享从最初的单线程服务模型一直演进到线 ...

  6. 持续集成时 travis 和 codecov 等 yaml 文件的配置

    最近在项目中在配置CodeCov 以及Travis 和 AppVeyor做持续集成时,遇到了一些问题,也解决了一些问题.顺便拿来分享一下. 首先时Travis,这个主要是来跑基于 Linux 环境下的 ...

  7. js异步梳理:1.从浏览器的多进程到JS的单线程,理解JS运行机制

    大家很早就知道JS是一门单线程的语言.但是也时不时的会看到进程这个词.首先简单区分下线程和进程的概念 1. 简单理解进程 - 进程是一个工厂,工厂有它的独立资源 - 工厂之间相互独立 - 线程是工厂中 ...

  8. Java中位运算符的使用

    先预知识: 数据在计算机中是以二进制的形式进行存储的,而二进制在内存中是以补码的形式进行存储的.在介绍位运算之前,首先来看一下原码.反码和补码的概念.由于正数的原码.反码和补码的形式都是一样的,所以以 ...

  9. c++容器加迭代器和python装饰器的对比

    c++利用对象实现简单数据的测试: class TestDataEmptyArray { public: static vector<int> get_array() { std::vec ...

  10. 一种表达式语言的解析引擎JEXL简单使用

    Jexl 是一个 Expression Language 的解析引擎, 是为了方便嵌入你的系统或者程序框架的开发中, 他算是实现了 JSTL 中 EL 的延伸版本. 不过也采用了一些 Velocity ...