zoukankan      html  css  js  c++  java
  • 《深度探索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;
    #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) = 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;
    #endif
    
    typedef 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

  • 相关阅读:
    Qt之加载QSS文件
    Qt之QSS(黑色炫酷)
    Sublime Text 2 快捷键
    QTablewidget 简单例子
    QTableview 只显示横向线
    Qt删除文件夹
    Ubuntu(Debian)apt-get
    C++中char*与wchar_t*之间的转换
    Qtl和JS、HTML通信/交互
    浅谈Socket编程
  • 原文地址:https://www.cnblogs.com/fengbohello/p/6261873.html
Copyright © 2011-2022 走看看