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

如果有如下的类:

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. JavaScript 作用域的误区

    了解JavaScript的同学可能知道,JavaScript语言由于设计原因,导致语言本身存在很多先天性的不足,当然这并非设计者有意的,js语言最初是被设计来作为网页交互的脚本语言,依照现有的js语法 ...

  2. MD5_Util工具类代码

    package com.yby.mall.utils; import java.math.BigInteger; import java.security.MessageDigest; public ...

  3. asp.net core 依赖注入实现全过程粗略剖析(3)

    接着 前面,前面的过程是普遍常用的依赖注入解析过程,我们正常都是在startup类中注入依赖服务,但是,笔者这周开发的时候遇到个问题,不同服务的生命周期不同,不能调用服务.举个例子,AddDbCont ...

  4. staff

    staff英 [stɑ:f] 四大服. 美 [stæf] n.参谋;全体职员;管理人员;权杖adj.职员的;行政工作的;参谋的;作为正式工作人员的v.在…工作;为…配备职员;任职于第三人称单数: st ...

  5. Codeforces.449D.Jzzhu and Numbers(容斥 高维前缀和)

    题目链接 \(Description\) 给定\(n\)个正整数\(a_i\).求有多少个子序列\(a_{i_1},a_{i_2},...,a_{i_k}\),满足\(a_{i_1},a_{i_2}, ...

  6. 【Linux入门学习之】vi/vim编辑器必知必会

    vi 在当前打开的文件内容中翻页:PageUp.PageDown 一.我们为什么要学习vim编辑器? Linux的命令行界面下面有非常多的文本编辑器.比如经常听说的就有Emacs.pico.nano. ...

  7. 树莓派上配置electron记录

    首先是最新版本的树莓派镜像默认不开启ssh,所以烧写好系统之后没法ssh登录 解决方法就是在烧写的内存卡分区内建立一个ssh文件(无后缀名),这样启动的时候就有ssh服务了 在~/.bashrc里面添 ...

  8. microsoft viso 下载地址

    https://pan.baidu.com/s/1pLBhG19

  9. 3ds max学习笔记(十一)-- 修改器

    1.修改器列表: 将常用的修改器放放置在集里: 1.点击[配置]按钮,勾选[显示按钮] 选择[配置修改器集],在新出的弹窗里通过左右拖拽进行设置: 2,选择之后,点击[确定]进行保存:

  10. unique_ptr_c++11

    unique_ptr 替代了原来的auto_ptr,指向对象具有唯一性,即同一时间只能有unique_ptr指向给定对象(和auto_ptr不同是禁止拷贝语义,通过移动语义替代) unique_ptr ...