今天看虚继承以及虚函数继承时写了几个实例来加深一下理解。相关技术原理参见:c++虚继承对象的内存布局
代码1:
没有虚继承的情况下
#include<iostream>
using namespace std;
class A//定义基类A
{public:A(int i){ cout<<"A cons"<<endl;}
void virtual print(){cout<<"aaa"<<endl;};
};
class B : public A
{public:B(int n):A(n){ cout<<"B cons"<<endl;}
void virtual print(){cout<<"bbb"<<endl;};
};
class C : public A
{public:C(int n):A(n){cout<<"C cons"<<endl; }
// void print(){};
};
class D :public B,public C //类D的构造函数,在初始化表中对所有基类初始化
{public:D(int n):B(n),C(n){ cout<<"D cons"<<endl;}
// void virtual print(){cout<<"ddd"<<endl;}
};
void main()
{
D d(1);
d.B::print();
d.C::print();
d.print(); //maybe the 'print' in base 'B' of class 'D' or the 'print' in base 'A' of base 'C' of class 'D'
d.A::print(); //maybe the 'A' in base 'B' of class 'D' or the 'A' in base 'C' of class 'D'
cout<<"size of A:"<<sizeof(A)<<endl;
cout<<"size of B:"<<sizeof(B)<<endl;
cout<<"size of C:"<<sizeof(C)<<endl;
cout<<"size of D:"<<sizeof(D)<<endl;
}
运行结果:

代码2
有虚继承的情况下
#include<iostream>
using namespace std;
class A//定义基类A
{public:A(int i){ cout<<"A cons"<<endl;}
void virtual print(){cout<<"aaa"<<endl;}
};
class B : public virtual A //A作为B的虚基类
{public:B(int n):A(n){ cout<<"B cons"<<endl;}
void virtual print(){cout<<"bbb"<<endl;};
};
class C : public virtual A //A作为C的虚基类
{public:C(int n):A(n){cout<<"C cons"<<endl; }
// void virtual print(){};
};
class D :public B,public C //类D的构造函数,在初始化表中对所有基类初始化
{public:D(int n):A(n),B(n),C(n){ cout<<"D cons"<<endl;}
void virtual print(){cout<<"ddd"<<endl;};
};
void main()
{
D d(1);
d.B::print();
d.C::print();
d.print();
d.A::print();
cout<<"size of A:"<<sizeof(A)<<endl;
cout<<"size of B:"<<sizeof(B)<<endl;
cout<<"size of C:"<<sizeof(C)<<endl;
cout<<"size of D:"<<sizeof(D)<<endl;
}
运行结果:

代码3~5主要考察了虚继承的情况下各个类的size问题。。。相关技术原理参见
c++虚继承对象的内存布局
代码3:
#include <iostream>
using namespace std;
class A
{
//char k[3];
virtual aa(){};
};
class B : public A
{
//char j[3]; //加入一个变量是为了看清楚class中的vfptr放在什么位置
public:
virtual bb(){};
virtual xx(){};
virtual aa(){};
};
class C : public B
{
//char i[3];
public:
virtual cc(){};
};
int main()
{
cout<<sizeof(A)<<endl;
cout<<sizeof(B)<<endl;
cout<<sizeof(C)<<endl;
return 0;
}
运行结果:
4
4
4
因为B
和C没有添加任何数据成员,仅仅override类A的虚函数,所以大小不变。
当
基类含有虚函数,单从非virtual继承,并且派生类没有添加新的数据成员,就算继承一万次也是4,vptr还不是那一个吗?类的size会变吗?
代码4:
#include <iostream>
using namespace std;
class A
{
//char k[3];
virtual aa(){};
};
class B : public virtual A
{
//char j[3]; //加入一个变量是为了看清楚class中的vfptr放在什么位置
public:
//virtual bb(){};
//virtual xx(){};
//virtual aa(){};
};
class C : public virtual B
{
//char i[3];
public:
//virtual cc(){};
};
int main()
{
cout<<sizeof(A)<<endl;
cout<<sizeof(B)<<endl;
cout<<sizeof(C)<<endl;
return 0;
}
运行结果:
4
8
12
代码5:
#include <iostream>
using namespace std;
class A
{
//char k[3];
virtual aa(){};
};
class B : public virtual A
{
char j[3]; //加入一个变量是为了看清楚class中的vfptr放在什么位置
public:
virtual bb(){};
virtual xx(){};
virtual aa(){};
};
class C : public virtual B
{
char i[3];
public:
virtual cc(){};
};
int main()
{
cout<<sizeof(A)<<endl;
cout<<sizeof(B)<<endl;
cout<<sizeof(C)<<endl;
return 0;
}
运行结果:
4
16
28
分析:
1、对于class A,由于只有一个虚函数,那么必须得有一个对应的虚函数表,来记录对应的函数入口地址。同时在class A的内存空间中之需要有个vfptr_A指向该表。sizeof(A)也很容易确定,为4。
2、对于class B,由于class B虚基础了class A,同时还拥有自己的虚函数。那么class B中首先拥有一个vfptr_B,指向自己的虚函数表。还有char j[3],做一次alignment,一般大小为4。可虚继承该如何实现咧?this is 啊 problem!偶之前是不晓得的,还好C++ Object Model上有介绍。首先要通过加入一个虚l类指针(记vbptr_B_A)来指向其父类,然后还要包含父类的所有内容。有些复杂了,不过还不难想象。sizeof(B)= 4+4+4+4=16(vfptr_B、char j[3]做alignment、vbptr_B_A和class A)。
3、在接着是class C了。class C首先也得有个vfptr_C,然后是char i[3],然后是vbptr_C_B,然后是class B,所以sizeof(C)=4+4+4+16=28(vfptr_C、char i[3]做alignment、vbptr_C_A和class B)。
2、对于class B,由于class B虚基础了class A,同时还拥有自己的虚函数。那么class B中首先拥有一个vfptr_B,指向自己的虚函数表。还有char j[3],做一次alignment,一般大小为4。可虚继承该如何实现咧?this is 啊 problem!偶之前是不晓得的,还好C++ Object Model上有介绍。首先要通过加入一个虚l类指针(记vbptr_B_A)来指向其父类,然后还要包含父类的所有内容。有些复杂了,不过还不难想象。sizeof(B)= 4+4+4+4=16(vfptr_B、char j[3]做alignment、vbptr_B_A和class A)。
3、在接着是class C了。class C首先也得有个vfptr_C,然后是char i[3],然后是vbptr_C_B,然后是class B,所以sizeof(C)=4+4+4+16=28(vfptr_C、char i[3]做alignment、vbptr_C_A和class B)。