• 带有虚表的类的内存分布总结


    这个问题一直似是而非的,昨天闲着无事,便细看一下,发现还是挺容易的。

    总结起来可以分为以下几块:

    1、空类的内存分布

    2、带变量的类的内存分布

    3、带虚函数的类的内存分布

    4、带虚函数的子类的内存分布

    5、关于虚析构的描述

    6、关于纯虚函数为何必须在子类中实现的问题。

    未完成部分:

    1、关于虚基类的结构分布。

    1、空类的内存分布比较简单,一般用一个字节表示,据说是为了标识类而作的特别的安排。如下代码:

    class A{}

    则sizeof(A) 为1.

    2、如果类中包含变量,则类的大小为变量的大小。

    3、类中一旦带有虚函数,则类的大小增加4个字节,前4个字节(针对32位机器)为虚表的入口地址,此地址指向一个数组,用来存放虚函数的地址

    4、子类中虚表指向的数组,对于未覆盖的虚函数,直接沿用父类的虚函数地址,已经覆盖的则改写成子类的虚函数地址

    5、虚析构函数也是虚函数,在虚表数组的最后一个,由于虚析构调用时由操作系统加入某些参数,因此不能手工调用。

    6、我们知道,纯虚函数的接口在子类中必须全部实现,否则程序会出错,原因是纯虚函数在父类中由于没有实现,系统指向的是一个错误地址,子类若有部分未实现的话,会依样把那些地址也放入虚表中,造成错误。

    最后以一个简单的例子来结束,代码可以打印出各变量及虚表的地址:

    #include "stdafx.h"
    #include < iostream >
    using namespace std;
    
    class Base {
    public:
        Base() {
            cout << "In Base" << endl;
            cout << "Virtual Pointer = " << (int*)this << endl;
            cout << "Address of Vtable = " << (int*)*(int*)this << endl;
            cout << "Value at Vtable 1st entry = " << (int*)*((int*)*(int*)this+0) << endl;
            cout << "Value at Vtable 2nd entry = " << (int*)*((int*)*(int*)this+1) << endl;
            cout << endl;
        }
        int base_;
        virtual void f1() = 0;
        virtual void f2() = 0;
    };
    
    
    class MostDrive : public Base {
    public:
        MostDrive() {
            cout << "In MostDrive" << endl;
            cout << "Virtual Pointer = " << (int*)this << endl;
            cout << "Address of Vtable = " << (int*)*(int*)this << endl;
            cout << "Value at Vtable 1st entry = " << (int*)*((int*)*(int*)this+0) << endl;
            cout << "Value at Vtable 2nd entry = " << (int*)*((int*)*(int*)this+1) << endl;
            cout << endl;
        }
        void test() {
            cout << "------------------------test---------------------"<<endl;
            cout << "In Drive" << endl;
            cout << "Virtual Pointer = " << (int*)this << endl;
            cout << "Address of Vtable = " << (int*)*(int*)this << endl;
            cout << "Value at Vtable 1st entry = " << (int*)*((int*)*(int*)this+0) << endl;
            cout << "Value at Vtable 2nd entry = " << (int*)*((int*)*(int*)this+1) << endl;
            cout << endl;
        }
        virtual void f1() { cout << "MostDrive::f1" << endl; }
        virtual void f2() { cout << "MostDrive::f2" << endl; }
        int mostdrive_;
    };
    typedef void(*Fun)();
    int main() {
        MostDrive d;
        d.base_ = 1;
        d.mostdrive_ = 3;
        d.test();
        cout << "------------in main()-----------------------";
        cout << "sizeof(MostDrive)=" <<sizeof(MostDrive) << endl;
        cout << "Virtual Pointer = " << (int*)&d << endl;
        cout << "Address of Vtable = " << (int*)*(int*)&d << endl;
        cout << "Value at Vtable 1st address = " << ((int*)*(int*)&d+0) << endl;
        cout << "Value at Vtable 1st entry = " << (int*)*((int*)*(int*)&d+0) << endl;
        cout << "Value at Vtable 2nd address = " << ((int*)*(int*)&d+1) << endl;
        cout << "Value at Vtable 2nd entry = " << (int*)*((int*)*(int*)&d+1) << endl;
        Fun pFun1 = (Fun)*((int*)*(int*)&d+0);
        pFun1();
        Fun pFun2 = (Fun)*((int*)*(int*)&d+1);
        pFun2();
        cout << "first value address = " <<(int*)(int*)&d + 1 <<endl;
        cout << "first value = " << *((int*)&d + 1) << endl;
        cout << "second value address = " <<(int*)(int*)&d + 2 <<endl;
        cout << "second value = " << *((int*)&d + 2) << endl;
        return 0;
    }

    运行结果:

    In Base
    Virtual Pointer = 0012FF58
    Address of Vtable = 004184D8
    Value at Vtable 1st entry = 004111DB
    Value at Vtable 2nd entry = 004111DB

    In MostDrive
    Virtual Pointer = 0012FF58
    Address of Vtable = 00417940
    Value at Vtable 1st entry = 00411145
    Value at Vtable 2nd entry = 004110C8

    ------------------------test---------------------
    In Drive
    Virtual Pointer = 0012FF58
    Address of Vtable = 00417940
    Value at Vtable 1st entry = 00411145
    Value at Vtable 2nd entry = 004110C8

    ------------in main()-----------------------sizeof(MostDrive)=12
    Virtual Pointer = 0012FF58
    Address of Vtable = 00417940
    Value at Vtable 1st address = 00417940
    Value at Vtable 1st entry = 00411145
    Value at Vtable 2nd address = 00417944
    Value at Vtable 2nd entry = 004110C8
    MostDrive::f1
    MostDrive::f2
    first value address = 0012FF5C
    first value = 1
    second value address = 0012FF60
    second value = 3

    图示如下:

  • 相关阅读:
    linux查看端口被占用等常用命令
    python批量修改文件内容及文件编码方式的处理
    为什么在Python里推荐使用多进程而不是多线程
    python小练习之读取文件写入excel
    python 小练习之生成手机号码
    python 小练习之删除文件夹下的所有文件,包括子文件夹中的文件
    python中 字符 字典 列表之间的转换
    统计表中 重复出现 XX次以上的数据
    java数据类型
    字符编码和python使用encode,decode转换utf-8, gbk, gb2312
  • 原文地址:https://www.cnblogs.com/luhouxiang/p/2747984.html
Copyright © 2020-2023  润新知