/********************************************
*@author: weedge
*@date: 19/07/2011
*@coment:
c++对象模型,类在内存中的分配情况,主要是对类中引入虚函数以及虚继承的情况的了解
_vptr:指向存放虚函数地址数组_vtable的指针。
_vtable:存放类中虚函数地址的数组。
typedef void (__cdecl *PVFN)(void);//通用虚函数指针PVFN
typedef struct{
//为了支持RTTI(Run-Time Type Identification)机制:运行时检查对象类型信息。
//为每个多态类创建一个type_info对象,并保存在vtable中的固定位置(一般为第一个位置,取决于编译器)
type_info *_pTypeInfo;
PVFN _arrayOfPvfn[];//虚函数个数由初始语句确定
}VTABLE;
基类A 和 C;
B继承A;
AC多继承A 和 C;
AA和BB虚继承A, AABB多继承AA和BB;
************************************************/
#include<iostream>
using namespace std;
class A
{
/*
在类中有虚函数的情况下:
类中隐藏了指向装有指向虚函数指针的数组的指针 _vptr;
而该虚函数的地址存放在_vtable中;
_vtable分配在静态数据区域,_vptr是类隐藏的数据成员。
*/
public:
A():a(0){printf("this is A CLASS\n");}
virtual ~A(){}
int get_a()const{return a;}
void set_a(int a){this->a = a;}
private:
int a;
static int count;//静态数据区域,不计入类的分配空间中。
};
class C
{
public:
C():c(0){printf("this is C CLASS\n");}
virtual ~C(){}
int get_c()const{return c;}
void set_c(int c){this->c = c;}
private:
int c;
};
class B : public A
{
/*
公有继承:A的成员属性权限不变。
其B中虚函数的地址放入B中的_vtable中,B中隐藏的数据成员_vptr指向该虚表_vtable。
由于是单继承,如果基类A中有_vptr数据成员,则子类B中的也是同一个_vptr成员(继承)。
*/
public:
B():b(0){printf("this is B CLASS\n");}
virtual ~B(){}
int get_b()const{return b;}
void set_b(){this->b = b;}
private:
int b;
};
class BB : virtual public A
{
/*
虚继承:基类A中的成员函数变为虚函数,作为子类BB中的成员函数,
与不使用虚继承不同的是BB中会重新分配一个隐藏数据成员_vptr,
其指向存有A类中所有函数地址数组_vtable的指针。
而BB中虚函数的地址放入BB中的_vtable中,BB中隐藏的数据成员_vptr指向该虚表_vtable。
这样存在两个指向不同虚表地址的_vptr数据成员。
虚继承主要是用于“菱形继承”的情况,虚继承抽象基类,这样子类中有2个不同虚表,
防止下个子类中的实例对象中调用抽象基类的函数成员时,出现“二义性”。
*/
public:
BB():bb(0){printf("this is BB CLASS\n");}
virtual ~BB(){}
int get_bb()const{return bb;}
void set_bb(){this->bb = bb;}
private:
int bb;
};
class AA : virtual public A
{
public:
AA():aa(0){printf("this is AA CLASS\n");}
virtual ~AA(){}
int get_aa()const{return aa;}
void set_aa(){this->aa = aa;}
private:
int aa;
};
class AC : public A, public C
{
/*
多继承:派生类从多个基类继承。
派生类从每个分支中继承一个vptr,编译器生成多个vtable,一一对应。
至于派生类AC中的虚函数地址应该是放入其中一个vtable中,具体情况待进一步了解。
*/
public:
AC():ac(0){printf("this is AC CLASS\n");}
virtual ~AC(){}
int get_ac()const{return ac;}
void set_ac(){this->ac = ac;}
private:
int ac;
};
class AABB : public AA, public BB
{
/*
多继承:派生类从多个基类继承。
派生类从每个分支中继承一个vptr,编译器生成多个vtable,一一对应。
至于派生类AC中的虚函数地址应该是放入其中一个vtable中,具体情况待进一步了解。
但是这里的继承属于“菱形继承”的情况,即为了防止AABB中对基类A中的成员函数访问出现“二义性”,
将A的派生类AA和BB采用虚继承。所以派生类AA和派生类BB中有指向同一个基类A中vtable的vptr,
即AA和BB的子类AABB也同时拥有一个隐藏的数据成员vptr.
*/
public:
AABB():aabb(0){printf("this is AABB CLASS\n");}
virtual ~AABB(){}
int get_aabb()const{return aabb;}
void set_aabb(){this->aabb = aabb;}
private:
int aabb;
};
int main()
{
cout<<sizeof(A)<<endl;//所以A的分配空间大小为sizof(int)+ sizeof(PVFN*) = 8
cout<<sizeof(B)<<endl;//所以B的分配空间大小为2*sizof(int)+ sizeof(PVFN*) = 12
cout<<sizeof(BB)<<endl;//所以BB的分配空间大小为2*sizof(int)+ 2*sizeof(PVFN*) = 16
cout<<sizeof(AC)<<endl;//所以AC的分配空间大小为3*sizof(int)+ 2*sizeof(PVFN*) = 20
cout<<sizeof(AABB)<<endl;//所以AABB的分配空间大小为4*sizof(int)+ 3*sizeof(PVFN*) = 28
return 0;
}