C++ 虚继承与继承的差异
上一篇 /
下一篇 2012-10-10 13:58:44
/ 个人分类:C++
4IcG/h|yS0 前面一篇文章,说明了在C++ 虚继承对基类构造函数调用顺序的影响。经过仔细推敲,发现没有彻底说清楚虚继承与普通继承之间的关系。所以用下面的文字再说明一下。
[ Q#T:zw9J^/IV051Testing软件测试网#B)~3M
X,nisg+A 首先,重复一下虚拟继承与普通继承的区别有:51Testing软件测试网/E
Vftn3Y_/V6k9D
51Testing软件测试网4l.fB:]G0l:r[f 假设derived 继承自base类,那么derived与base是一种“is a”的关系,即derived类是base类,而反之错误;51Testing软件测试网#~?\*UF8h
1D[ Dt{ `,p2V0 假设derived 虚继承自base类,那么derivd与base是一种“has a”的关系,即derived类有一个指向base类的vptr。
?,S7Y/F]3vY0ex?w m;UF}0 因此虚继承可以认为不是一种继承关系,而可以认为是一种组合的关系。因为虚继承有着“继承”两个关键字,那么大部分人都认为虚继承与普通继承的用法没什么太大的不同。由此用在继承体系中,这种将虚继承认为是普通继承的危害更佳大。下面先用一个例子来说明问题:51Testing软件测试网;CA1ZOV|_
Zr:g#Wd"Kva.XI0class base51Testing软件测试网y-C;I2s5G { ,ayb|x|O&c0public: 2]8z L)M8yy:W0 base(){cout<<"base::base()!"<<endl;}51Testing软件测试网 Pnl*I
k)H void printBase(){cout<<"base::printBase()!"<<endl;} i%kE-evcW$ug7r0};51Testing软件测试网M'~
~Ts.Y,f+k *X[b*nS3{7C0class derived:public base Q1RS/R7b0{ X2V-GQL8YV+Gm0public:51Testing软件测试网9`,eL-LH
TS6ei3j,Mm derived(){cout<<"derived::derived()!"<<endl;} \ZbO_ {SV Av0 void printDerived(){cout<<"derived::printDerived()!"<<endl;}51Testing软件测试网AAX"~E!Y
N1X };51Testing软件测试网q#r8PtVi^
s |
51Testing软件测试网|,R!N:F0rV"a~ 上面是普通继承实现,在实际应用中,我们可以使用下面的代码进行类型转换:
S-k#Sw0Q:e)M0int main(int argc, const char * argv[]) M#y%J7t4L)l:Ui0{51Testing软件测试网b
s0w+a;]
U/m'im derived oo;51Testing软件测试网kI7Lg
w#{H |&`^ base oo1(static_cast<base>(oo)); %?[bx6_m0d@;qS0 oo1.printBase();51Testing软件测试网0`6P~]'W5J2{ derived oo2 = static_cast<derived&>(oo1);51Testing软件测试网9I5qX[;YSR7G$I#v'[ oo2.printDerived(); !Q#A#CEK@0 return 0;51Testing软件测试网8p,Z,p'L&p0u,wC } |
51Testing软件测试网B` })?+dh3V!l
b 编译无错误,而且会得出正确的结果。其结果为:
#wP0F7GM.xOztP.x3P051Testing软件测试网pu9dH;Xd0K:s base::base()!
#v2~Zy.`1KE|2O0 derived::derived()!
g&T_f y;`m0 base::printBase()!51Testing软件测试网fB9E f-W
kKW"cZ&z
derived::printDerived()!
`}1W#}/uC0$h6JG
K6{o r0 而将上面的普通继承变成虚拟继承,如下代码:51Testing软件测试网EMz*ni;|(Ex.i
51Testing软件测试网1Yq\uk6Jm class base151Testing软件测试网f5j,{i~ {51Testing软件测试网+KJ._:[b\A3lj@ public:51Testing软件测试网~9WTr"MA base1(){cout<<"base::base()!"<<endl;}51Testing软件测试网6^"f
kva!g$N
[z7|k void printBase(){cout<<"base::printBase()!"<<endl;}51Testing软件测试网-g5f8E5T9Ti };51Testing软件测试网,x!s_,w1J!u*T;x 51Testing软件测试网Ob7k
lO{#ZvOW2Jclass derived1:virtual public base1 e v3B6jSo4zF0{ k&H|1[ke#Q)o0public:51Testing软件测试网d:a7J3|Q derived1(){cout<<"derived::derived()!"<<endl;}51Testing软件测试网Dtgc,N void printDerived(){cout<<"derived::printDerived()!"<<endl;} 5@JKzE*A%H:In,a0};51Testing软件测试网7{K%t\D/P 51Testing软件测试网E8c)cmaVint main(int argc, const char * argv[]) 8iOCQ0}8g0{ 6k)pV1C@0^,E2A0 derived1 oo; ks1h g5KX-Z0 base1 oo1(static_cast<base1>(oo)); 6e,u@vDF.F:B\)R0 oo1.printBase();51Testing软件测试网 H ^)j/PKq5o derived1 oo2 = static_cast<derived1&>(oo1); Q)Q]FU5B:c#\0 oo2.printDerived(); f ?6@e*P5e"hC0 return 0;51Testing软件测试网'l[r
q-^ }51Testing软件测试网,yjisi,@
HJ8x |
8WV} W1h o0 编译上面的代码,提示如下:
n.oBb!TC.W0
f#g9HE6TMq0 可以看到不能将基类通过static_cast转换为继承类。我们知道c++提供的强制转换函数static_cast对于继承体系中的类对象的转换一般是可行的。那么这里为什么就不可以了呢?还是需要从虚拟继承的内部实现来说明问题。51Testing软件测试网Qjdnq
virtual base class的原始模型是在class object中为每一个有关联的virtual base
class加上一个指针vptr,该指针指向virtual基类表。有的编译器是在继承类已存在的virtual
table直接扩充导入一个virtual base class
table。不管怎么样由于虚继承已完全破坏了继承体系,不能按照平常的继承体系来进行类型转换。51Testing软件测试网${$L{ ot F%]5s
不管怎么样,虚继承在类型转换是一定要十分注意。不要轻易使用虚继承,更不要在虚继承的基础上进行类型转换,切记切记!51Testing软件测试网1xEZ/bIT@,l
收藏
举报
TAG: