C++ 虚继承对基类构造函数调用顺序的影响-1

上一篇 / 下一篇  2012-10-09 10:43:38 / 个人分类:C++

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$P m0class 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软件测试网4mtJ0MO YTd V

51Testing软件测试网{%\!~ @ qx(f

class iistream:virtual stream51Testing软件测试网2`5^ i5T6U$m$@@
{
`D x5o1qL0public:
\,RK-f'|\/~4f0    iistream(){cout<<"istream::istream()!"<<endl;}51Testing软件测试网 \TO0N~ c[
};

0?)BqgwQ3v|051Testing软件测试网`vBh iR%O F

class 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_/Zh

class iiostream:public iistream,public oostream
%_`G't w,b%\B1C-Wq0{
YW?]H5[/d0public:
f|extHr,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[])
+MFCp5D7}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软件测试网H r`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`

  输出这样的结果是毫无悬念的!本来虚拟继承的目的就是当多重继承出现重复的基类时,其只保存一份基类。减少内存开销。其继承结构为:

!v R3}8~ rRT2\0

:l!{p5G'?(liR0  stream51Testing软件测试网#DR` LKsLM?
  /               \51Testing软件测试网b#gR#pA
  istream   ostream51Testing软件测试网i"C iSq+F E7p
  \                 /
t{4{T%Rhtv4do0  iiostream
51Testing软件测试网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(I0

z,K O bs0  而现在我们换种方式使用虚继承:51Testing软件测试网a-l"B#m1Zf$m$O

51Testing软件测试网0w(X9}xQYSID

51Testing软件测试网wcqu!@

51Testing软件测试网\0jR1vE+}3[

class stream51Testing软件测试网I&d axx.f
{
z4Hp6~-N A.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*v A;[0    iistream(){cout<<"istream::istream()!"<<endl;}
H[8iMEF[@0};

4^o$u qF\p P p051Testing软件测试网_'?n!E u(l&ob:j

class 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(Y8tS ce-A

51Testing软件测试网5g9m)wxa [

class iiostream:virtual iistream,virtual oostream51Testing软件测试网vq}!O'd R
{
$jt6])Y'q3J u L0public:
r3|ig{I'F.vU0    iiostream(){cout<<"iiostream::iiostream()!"<<endl;}
(U:T9^GaO:W0};
51Testing软件测试网7?/vd)G!]2A

51Testing软件测试网KO]:m^

int main(int argc, const char * argv[])51Testing软件测试网 U7R ctn Nuu
{51Testing软件测试网TZimFb h*^
    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 M X[a*F

.j5v&c5{S B;O0  从结果可以看到,其构造过程中重复出现基类stream的构造过程。这样就完全没有达到虚拟继承的目的。其继承结构为:51Testing软件测试网gw3cr7U5bw

d obv\#H;b6^7A0  stream              stream
n$Q L p5rK4_,Z:[0  \                     /
R pi o}0  istream    ostream51Testing软件测试网m:[x/\b:l/G
  \                   /
5Z;SJH:Ou"|P0  iiostream
51Testing软件测试网?_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&` l g7xrT+T0main()
I6_psS R#Y3p0{51Testing软件测试网?5Q(x%QIf`
  iiostream ii;51Testing软件测试网%i9tX"joG g
  ii.f();51Testing软件测试网9VE5kf}eyW
}

TAG:

 

评分:0

我来说两句

Open Toolbar