#include <iostream>
using namespace std;
//本程序在VS2010 和 Linux 下测试。
/*类之间的关系图:
_____
|__X__|
/v \v
_____ _____
|__Y__| |__Z__|
(v)\ _____ /(v)
|__A__|
|
_____
|__B__|
*/
class X
{
public:
X(int a): x(a){};
virtual ~X(){};
//protected:
int x;
};
class Y: virtual public X
{
public:
Y(int a, int b): X(a), y(b){};
//protected:
int y;
};
class Z: virtual public X
{
public:
Z(int a, int b): X(a), z(b){};
//protected:
int z;
};
/*
class A: public Y, public Z //A不是虚继承
{
public:
A(int ax, int bx, int cx): X(ax), Y(ax, bx), Z(ax, bx), a(cx){};
// virtual void test(){};
int a;
};
*/
/*
class B: public A //A不是虚继承
{
public:
B(int ax, int bx, int cx, int dx): X(ax), A(ax, bx, cx), b(dx){};
int b;
};
*/
class A: virtual public Y, virtual public Z//A是虚继承
{
public:
A(int ax, int bx, int cx): X(ax), Y(ax, bx), Z(ax, bx), a(cx){};
int a;
};
class B: public A //A是虚继承
{
public:
B(int ax, int bx, int cx, int dx): X(ax), Y(ax, bx), Z(ax, bx), A(ax, bx, cx), b(dx){};
int b;
};
int main()
{
X xx(1);
Y yy(1, 2);
Z zz(1, 2);
A aa(1, 2, 3);
B bb(1, 2, 3, 4);
cout<<"SIZE of xx: "<<sizeof(xx)<<endl; //8
cout<<"address of xx && xx.x: "<<&xx<<" "<<&xx.x<<endl; // 0013F910 0013F914 说明vptr放在成员之前,布局为:vptr_x, x
cout<<"SIZE of yy: "<<sizeof(yy)<<endl; //16
cout<<"address of yy && yy.y && yy.x: "<<&yy<<" "<<&yy.y<<" "<<&yy.x<<endl;//0028F8F8 0028F8FC 0028F904 说明布局为: vptr_y, y, vptr_x, x
cout<<"SIZE of zz: "<<sizeof(zz)<<endl; //16 同Y
cout<<"address of zz && zz.z && zz.x: "<<&zz<<" "<<&zz.z<<" "<<&zz.x<<endl;
cout<<"SIZE of aa: "<<sizeof(aa)<<endl; //28 A不是虚继承, 且A的所有虚函数已经包含在X中了,所以自己不需要vptr_a,如果A中添加虚函数test则在最顶端添加vptr_a
//32 A是虚继承,有vprt_a
cout<<"address of aa && aa.a && aa.y && aa.z && aa.x: "<<&aa<<" "<<&aa.a<<" "<<&aa.y<<" "<<&aa.z<<" "<<&aa.x<<endl;
//A不是虚继承:0025FA3C 0025FA4C 0025FA40 0025FA48 0025FA54 布局为vptr_y, y, vptr_z, z, a, vptr_x, x (先确定基类)
//A是虚继承: 001BF800 001BF804 001BF814 001BF81C 001BF80C 布局为vptr_a, a, vptr_x, x, vptr_y, y, vptr_z, z(先确定A中不变部分)
cout<<"SIZE of bb: "<<sizeof(bb)<<endl; //32 A不是虚继承
//36 A是虚继承
cout<<"address of bb && bb.y && bb.z && bb.a && bb.b && bb.x: "<<&bb<<" " <<&bb.y<<" "<< &bb.z<<" "<<&bb.a<<" "<<&bb.b<<" "<<&bb.x<<endl;
//A不是虚继承: 0027F954 0027F958 0027F960 0027F964 0027F968 0027F970 布局为vptr_y, y, vptr_z, z, a, b, vptr_x, x
//A是虚继承: 0022F78C 0022F7A4 0022F7AC 0022F790 0022F794 0022F79C 布局为vptr_a, a, b, vptr_x, x, vptr_y, y, vptr_z, z
}
vptr放在数据成员前。
a:
1. 对于普通继承(不管包不包括虚函数),都是按照继承顺序从左至右先为基类对象分配内存,再为派生类分配;
2. 存在虚函数时,如果派生类中没有新增虚函数,则只需要基类的虚函数指针vptr即可,否则还要新增一个自己的vptr,多重继承时每个包含虚函数的分支的基类都要有vptr;
b:
虚继承时,先为本类中不变部分分配内存,再确定共享部分的内存;虚继承一定需要vptr来存储共享部分的偏移。