51Testing软件测试网
[:Csnsx 继承作为面向对象编程的一种基本特征,其使用频率非常高。而继承包含了虚拟继承和普通继承,在可见性上分为public、protected、private。可见性继承比较简单,而虚拟继承对学习c++的难度较大。51Testing软件测试网P-Q$TY0v([.^
+uHZ_$fe0 首先,虚拟继承与普通继承的区别有:
Su\\i/M hEe051Testing软件测试网8G4F(sj};y_6ol 假设derived 继承自base类,那么derived与base是一种“is a”的关系,即derived类是base类,而反之错误;51Testing软件测试网'j,_f\e
-@*iOw+p5];_YH0 假设derived 虚继承自base类,那么derivd与base是一种“has a”的关系,即derived类有一个指向base类的vptr。(貌似有些牵强!某些编译器确实如此)
1Z3]Xq
T0]+X t)kt1Wr0 因此虚继承可以认为不是一种继承关系,而可以认为是一种组合的关系。正是因为这样的区别,下面我们针对虚拟继承来具体分析。虚拟继承中遇到最广泛的是菱形结构。下面从菱形虚继承结构说起吧:
:}"|_Hp(m _;Xmf0
Z
m0W`-lB$Pm0class stream51Testing软件测试网,|5M(SKF!J H!Z)u;k {51Testing软件测试网~q7gH
Kb5Y?*Z public: dR&QU(S6V{Q0 stream(){cout<<"stream::stream()!"<<endl;}51Testing软件测试网'S.t!j}o,iy };51Testing软件测试网4mtJ0MOYTdV 51Testing软件测试网{%\!~@ qx(fclass iistream:virtual stream51Testing软件测试网2`5^i5T6U$m$@@ { `D
x5o1qL0public: \,RK-f'|\/~4f0 iistream(){cout<<"istream::istream()!"<<endl;}51Testing软件测试网
\TO0N~c[ }; 0?)BqgwQ3v|051Testing软件测试网`vBhiR%O
Fclass oostream:virtual stream wy.YF3dl0{51Testing软件测试网1H8M'Y {+@p$zc public: }P4Twsli%s/d7p)P0 oostream(){cout<<"ostream::ostream()!"<<endl;}51Testing软件测试网3yp1N+G-Ub }; 0NUZ0H\2Q051Testing软件测试网;c'wB_/Zhclass iiostream:public iistream,public oostream %_`G't
w,b%\B1C-Wq0{ YW?]H5[/d0public: f|ex tHr,K0 iiostream(){cout<<"iiostream::iiostream()!"<<endl;}51Testing软件测试网lS2N#P}vI([ wV };51Testing软件测试网
O^[qa8G;x z`O6pJ[k+kl-GN0int main(int argc, const char * argv[]) +MFC p5D7}0{ NgVi)_#T'I Y1~0 iiostream oo;51Testing软件测试网.W(~mS5GVS } 'nZM7X GC0 |
51Testing软件测试网-Lk`YauA"f 程序运行的输出结果为:
D"l!r.n'm051Testing软件测试网gzLk;]%r4S stream::stream()!
y%J*w*Wc(W
f!T[0 istream::istream()!51Testing软件测试网Hr`3|+PySn;\YE
ostream::ostream()!
3g
D0s`d(Z#h{P0 iiostream::iiostream()!51Testing软件测试网A!WdLE&c!Bw}6L
51Testing软件测试网|d#Ct;gJ!`:V|V` 输出这样的结果是毫无悬念的!本来虚拟继承的目的就是当多重继承出现重复的基类时,其只保存一份基类。减少内存开销。其继承结构为:
!vR3}8~ rRT2\0:l!{p5G'?(liR0 stream51Testing软件测试网#DR` LKsLM?
/ \51Testing软件测试网b#gR#pA
istream ostream51Testing软件测试网 i"CiSq+FE7p
\ /
t{4{T%Rhtv4do0 iiostream51Testing软件测试网h[g}8l\wW
:l
]1YgG3nB/?]0 这样子的菱形结构,使公共基类只产生一个拷贝。
M!QJ!w:~.v051Testing软件测试网W(x8Q0qci2{
从基类 stream 派生新类时,使用 virtual
将类stream说明为虚基类,这时派生类istream、ostream包含一个指向虚基类的vptr,而不会产生实际的stream空间。所以最终
iiostream也含有一个指向虚基类的vptr,调用stream中的成员方法时,通过vptr去调用,不会产生二义性。
MI_4d9ht?pZ7h(I0z,K
O bs0 而现在我们换种方式使用虚继承:51Testing软件测试网a-l"B#m1Zf$m$O
51Testing软件测试网0w(X9}xQYSID51Testing软件测试网wcqu!@
51Testing软件测试网 \0jR1vE+}3[ class stream51Testing软件测试网I&d
axx.f { z4Hp6~-NA.s`3IM0public: N-y jQ4[uPbH0z0 stream(){cout<<"stream::stream()!"<<endl;} 0R:bSs g[0};51Testing软件测试网IE;[}kC R8|,i:tYPn4\'~V0class iistream:public stream51Testing软件测试网$z` e:n~4ge7^Ow { D+A*L9yY.IF)i0public: J"l*vA;[0 iistream(){cout<<"istream::istream()!"<<endl;} H[8iMEF[@0}; 4^o$uqF\p
Pp051Testing软件测试网_'?n!E u(l&ob:jclass oostream:public stream51Testing软件测试网I@6@7H*_1H#~ m { :PGy r I0public: !u}/L0S^a,S/`0 oostream(){cout<<"ostream::ostream()!"<<endl;} T:p^EW/t.h#u0};51Testing软件测试网:D,~5TS)wt'N(Y8tSce-A 51Testing软件测试网5g9m)wxa
[class iiostream:virtual iistream,virtual oostream51Testing软件测试网vq}!O'd
R { $jt6])Y'q3JuL0public: r3|ig{I'F.vU0 iiostream(){cout<<"iiostream::iiostream()!"<<endl;} (U:T9^GaO:W0};51Testing软件测试网7?/v d)G!]2A 51Testing软件测试网KO]:m^int main(int argc, const char * argv[])51Testing软件测试网U7R ctnNuu {51Testing软件测试网TZi mFbh*^ iiostream oo;51Testing软件测试网xE)gJ5oc } 7Kz
p6v%bC'Q0 |
%_2Ha-}2?sW&B2L8FP0 其输出结果为:51Testing软件测试网VT F;??3|fn
g{dt,]5r`3@$Y0 stream::stream()!
"^ R'z
Jsls9z0 istream::istream()!51Testing软件测试网J0P}5ofaX
stream::stream()!
{O,K;X,b0q!pQ/Y4u0 ostream::ostream()!51Testing软件测试网sE{*[A!\
iiostream::iiostream()!51Testing软件测试网M/k~7F MX[a*F
.j5v&c5{SB;O0 从结果可以看到,其构造过程中重复出现基类stream的构造过程。这样就完全没有达到虚拟继承的目的。其继承结构为:51Testing软件测试网gw3cr7U5bw
d
obv\#H;b6^7A0 stream stream
n$Q Lp5rK4_,Z:[0 \ /
R
pi
o}0 istream ostream51Testing软件测试网m:[x/\b:l/G
\ /
5Z;SJH:Ou"|P0 iiostream51Testing软件测试网?_T!cg9~u;T0L
51Testing软件测试网DTUDQq0u.U/x 从继承结构可以看出,如果iiostream对象调用基类stream中的成员方法,会导致方法的二义性。因为iiostream含有指向其虚
继承基类 istream,ostream的vptr。而
istream,ostream包含了stream的空间,所以导致iiostream不知道导致是调用那个stream的方法。要解决改问题,可以指定
vptr,即在调用成员方法是需要加上作用域,例如51Testing软件测试网0e6UF5\}'`Ep)V
51Testing软件测试网YdeDYy{@G)H%m4vW"G/F0class stream
Hj` cvA$B0{51Testing软件测试网%vt"w/\@/f;P1J
void f(){cout<<"here!"<<endl;}51Testing软件测试网qb4k*b Wi$@&O
}
;R&`lg7xrT+T0main()
I6_psS
R#Y3p0{51Testing软件测试网?5Q(x%QIf`
iiostream ii;51Testing软件测试网%i9tX"joG
g
ii.f();51Testing软件测试网9VE5kf}eyW
}