• C++ 虚函数表、函数地址、内存布局解析


    先看一下虚函数:

    class Base
    {
    public:
        virtual void Funtest1(int i)
        {
            cout << "Base::Funtest1()" << endl;
        }
        virtual void Funtest2(int i)
        {
            cout << "Base::Funtest2()" << endl;
        }

         void common(int i)
        {
         cout << "Base::common()" << endl;
        }

    int _data;
    };
    
    int main()
    {
        cout << sizeof(Base) << endl;
        Base b;
        b._data = 10;
        return 0;
    }

    8?不知道大家有没有问题,反正我是有疑惑了。以前在对象模型(https://blog.csdn.net/qq_39412582/article/details/80808754)时我提到过怎么来求一个类的大小。按照那个方法,这里应该是4才对啊,为什么会是8呢?

    通过观察。我们发现这个例子里面和以前不一样,类成员函数变成了虚函数,这是不是引起类大小变化的原因呢?
    我们假设就是这样,然后看看内存里是怎么存储的呢?
     

    可以看到它在内存里多了四个字节,它是一个指针,存储的是虚拟数列表的指针;

    我们来验证一下:

    typedef void(__stdcall *PVFT)(int);  //函数指针
    int main()
    {
        cout << sizeof(Base) << endl;
        Base b;
        b._data = 10;
        PVFT* pVFT = (PVFT*)(*((int*)&b));
        while (*pVFT)
        {
            (*pVFT)(1);
            pVFT += 1;
        }
    
        // 成员变量 _data
        int * pt =(int*) &b;
        pt += 1;
    
        cout << (*pt) << endl;
    
        return 0;
    }

    可以看到 C++ 虚函数表,以及成员在内存中的布局;

    派生类虚表:
    1.先将基类的虚表中的内容拷贝一份
    2.如果派生类对基类中的虚函数进行重写,使用派生类的虚函数替换相同偏移量位置的基类虚函数
    3.如果派生类中新增加自己的虚函数,按照其在派生类中的声明次序,放在上述虚函数之后
    https://coolshell.cn/articles/12176.html
    多态缺陷

    ●降低了程序运行效率(多态需要去找虚表的地址)
    ●空间浪费
     

    成员函数地址:

    typedef void (Base::*fun)(int);
    typedef void(__stdcall *PVFT)(int);  //函数指针
    int main()
    {
        cout << sizeof(Base) << endl;
        Base b;
        b._data = 10;
        PVFT* pVFT = (PVFT*)(*((int*)&b));
        while (*pVFT)
        {
            (*pVFT)(1);
            pVFT += 1;
        }
    
        // 成员变量 _data
        int * pt =(int*) &b;
        pt += 1;
    
        cout << (*pt) << endl;
        // 赋值
        fun f = &Base::common; 
         //使用
        (b.*f)(1);
        return 0;
    }
        fun f = &Base::common; 
         
        (b.*f)(1);

    当需要根据函数名来响应处理时

    结果:

    如果我们想取函数地址怎么办,直接强转会报错

    unsigned int a = reinterpret_cast<unsigned int>(f);//编译错误 

    其实我们知道类成员函数只是函数第一个参数是this指针,但是this指针不是通过普通函数参数压栈方式,而是放进ecx中。
  • 相关阅读:
    谷歌浏览器离线安装
    C语言restrict关键字的使用
    Win32编程中radiobutton的分组
    在SourceForge中建立开源项目
    [转载]Linux解压缩命令
    [转载]vim配置文件
    解决VC6在win7下打开文件崩溃问题
    gson解析复杂的json数据
    catch中return语句的执行时间
    踏出了学习clojure的第一步
  • 原文地址:https://www.cnblogs.com/sharecenter/p/14691001.html
Copyright © 2020-2023  润新知