zoukankan      html  css  js  c++  java
  • 带有虚表的类的内存分布总结

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

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

    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

    图示如下:

  • 相关阅读:
    .NET实现Excel文件的读写 未测试
    权限管理设计
    struts1中配置应用
    POJ 2139 Six Degrees of Cowvin Bacon(floyd)
    POJ 1751 Highways
    POJ 1698 Alice's Chance
    POJ 1018 Communication System
    POJ 1050 To the Max
    POJ 1002 4873279
    POJ 3084 Panic Room
  • 原文地址:https://www.cnblogs.com/luhouxiang/p/2747984.html
Copyright © 2011-2022 走看看