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

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

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

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

图示如下:

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

 

 

你可能感兴趣的:(总结)