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

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

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

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

图示如下:

 

 

posted @ 2012-10-31 14:33  绿色的麦田  阅读(458)  评论(0编辑  收藏  举报