虚基类分析

 1 #include<iostream>
 2 using namespace std;
 3 
 4 class ba{
 5 public:
 6     ba(){cout<<"ba"<<endl;}
 7     virtual char* vf() const=0;
 8 };
 9 
10 class bas:public ba{
11     int k;
12 public:
13     bas(int k){this->k=k;cout<<"bas k="<<k<<endl;}
14     char* vf() const=0;
15 };
16 class d1:virtual public bas{
17 public:
18     d1():bas(1){cout<<"d1"<<endl;}
19     char* vf() const { return "d1";}
20 };
21 class d2:virtual public bas{
22 public:
23     d2():bas(2){cout<<"d2"<<endl;}
24     char* vf() const { return "d2";}
25 };
26 class mi:public d1,public d2{
27 public:
28     mi():bas(3){cout<<"mi"<<endl;}
29     char* vf() const
30     {
31         return d1::vf();
32     }
33 };
34 class x:public mi{
35 public:
36     x():bas(4){cout<<"x"<<endl;}
37     char* vf() const
38     {
39         return "x";
40     }
41 };
42 int main()
43 {
44     x xx;
45     return 0;
46 }
View Code

以上代码输出结果是

ba

bas k=4

d1

d2

mi

x

由此可见虚继承时最晚派生类必须负责对虚拟基类的初始化。程序先跳至x类构造函数,然后跳至bas类构造函数进行虚拟基类的初始化,而bas是继承自ba的,因此跳至ba先进行ba的初始化。bas初始化完毕后跳至mi构造函数,再先跳至d1构造函数,构造完d1后跳至d2构造函数,然后再跳回mi构造函数构造mi。最后跳回x构造函数完成x的构造。

在d1中,虚基类的指针在虚函数的指针之前。而且因为这些指针的存在,会对类进行内存对齐。如果一个类含有一个虚函数指针,并有一个char类型成员,则这个类大小是8。

如果程序中添加以下四句话:

d1* pd1=&xx;
d2* pd2=&xx;
bas* pbas=&xx;
ba* pba=&xx;

可以发现pba和pbas是的值是一样的,说明虚继承时只存在基类的一份拷贝,而pd1和pd2的值不同,它们应该是d1地址和d2地址到基类地址的偏移值。

若再添加两句话:

x* px=&xx;
mi* pmi=&xx

可以发现px,pmi和pd1的值是一样的。

posted @ 2016-04-04 22:05  vaevaevae  阅读(164)  评论(0编辑  收藏  举报