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

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

%Q^W!Ay8}p0  继承作为面向对象编程的一种基本特征,其使用频率非常高。而继承包含了虚拟继承和普通继承,在可见性上分为public、protected、private。可见性继承比较简单,而虚拟继承对学习c++的难度较大。

+O6h g(n0['vx [{eI051Testing软件测试网,Sj|3Y vqWtt*I

  首先,虚拟继承与普通继承的区别有:

z#u]n0Dh:W5z0

F9[6^:IKF?0  假设derived 继承自base类,那么derived与base是一种“is a”的关系,即derived类是base类,而反之错误;

2OO%nrA bBK,HUa0

:RG[/BULT0  假设derived 虚继承自base类,那么derivd与base是一种“has a”的关系,即derived类有一个指向base类的vptr。(貌似有些牵强!某些编译器确实如此)51Testing软件测试网F&M5q3ohbF+jd+\G

,P]$w5kbg6`U1T x0  因此虚继承可以认为不是一种继承关系,而可以认为是一种组合的关系。正是因为这样的区别,下面我们针对虚拟继承来具体分析。虚拟继承中遇到最广泛的是菱形结构。下面从菱形虚继承结构说起吧:51Testing软件测试网5W Zsm0n?1y

1t5`W%Zz#vo0class stream51Testing软件测试网4e$?{3a-~hYs
{
iJ;WnxR q0public:
$EA1Ks"fPaO,sM0    stream(){cout<<"stream::stream()!"<<endl;}51Testing软件测试网u.Fu@ Dgt+e
};
51Testing软件测试网7[(n[NG

@#d+W"lNLr:A1BP6U;x j0class iistream:virtual stream51Testing软件测试网%o+\%WQhpDFC-L
{51Testing软件测试网"b:Uip#R~"LX
public:51Testing软件测试网!xO6?/t\t(mW
    iistream(){cout<<"istream::istream()!"<<endl;}51Testing软件测试网]eP C ^*q X f L&b
};
51Testing软件测试网-yS#n x5C {)y7S M

J.]c-T]A u,f0class oostream:virtual stream
Qu:nZ2M%I1_:YBA h0{51Testing软件测试网@"|T uf,S)P
public:51Testing软件测试网"T5l.x$Czf_
    oostream(){cout<<"ostream::ostream()!"<<endl;}
Zp_B-w3l!q O0};

.B Slsq4t"o0

n Z e/C-xp2m0class iiostream:public iistream,public oostream
(a-TA~!D0{51Testing软件测试网 Z7} LV9^D9C)C![a
public:
&~SC@pqAx0    iiostream(){cout<<"iiostream::iiostream()!"<<endl;}
[V'G$QF,Po'C F0};
51Testing软件测试网Zh2^Zq-@cU^-]c

51Testing软件测试网lW:|ei|O"e4c

int main(int argc, const char * argv[])
+@(o7M]@-O}0{
"r/J3^NuNJ0    iiostream oo;51Testing软件测试网#s9x;v ` W
51Testing软件测试网!t;|Ra~:|Lx9W

-ro"LG&P iN-g0  程序运行的输出结果为:

|:|Mju#N051Testing软件测试网f,wo9Kl8u@u

  stream::stream()!
K BddKP0  istream::istream()!51Testing软件测试网s^Po0\WMT
  ostream::ostream()!
2@/ArJ&e\1_| U0  iiostream::iiostream()!

\#|qDe0

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

7|-[4U)o dP C0

G0M!G7k'M?d `.jJ0  stream
DA)V(sV8T{ol H0  /               \
-J#kPVEW0  istream   ostream
I7x0m oo[0  \                 /
/}'z eG%MyXB0  iiostream

.a Zg Q\ A051Testing软件测试网 P} p'n$rK9}`

  这样子的菱形结构,使公共基类只产生一个拷贝。51Testing软件测试网&p2{c `.K;Kb!Mw

]!Zpcw0   从基类 stream 派生新类时,使用 virtual 将类stream说明为虚基类,这时派生类istream、ostream包含一个指向虚基类的vptr,而不会产生实际的stream空间。所以最终 iiostream也含有一个指向虚基类的vptr,调用stream中的成员方法时,通过vptr去调用,不会产生二义性。51Testing软件测试网8a.\R#deC4u_9P

1b4V(Q8Z1P3~"Xi*kn"c0  而现在我们换种方式使用虚继承:51Testing软件测试网"p:@[)fk-E

x?kvt};i ey({ n051Testing软件测试网.J*K x@K)Vr2~

51Testing软件测试网 yJ9yM0b u,r

class stream
R6L"mY1I0{
I j#T,kAh4w(g0public:51Testing软件测试网C_[ UNB
    stream(){cout<<"stream::stream()!"<<endl;}51Testing软件测试网q4Q`XT&p
};

o?^P*^\y A H!k051Testing软件测试网b]F?fq

class iistream:public stream51Testing软件测试网 l Qw^5js;xiK
{
h8m'`(K%acR0public:
k ?(F6WU-Kr0    iistream(){cout<<"istream::istream()!"<<endl;}51Testing软件测试网%wk `"VH%s
};

zO.{oV'{0

s5W K0@6C2I0class oostream:public stream
F6s-t'gYpk^| G0{
9Qy)L$c2G:l0n,y R'mr0public:51Testing软件测试网$mo |9~I(Y4f~J0k
    oostream(){cout<<"ostream::ostream()!"<<endl;}
"G@5h B"B'j0};
51Testing软件测试网'q4{M'zk.j0i

+Xb sV)d Ei0class iiostream:virtual iistream,virtual oostream
*Jz r7nW3E@0{51Testing软件测试网tn?+EZ9pwRP&d
public:51Testing软件测试网&z0y V T Y"mjt&A
    iiostream(){cout<<"iiostream::iiostream()!"<<endl;}
)ug\Y-m"q)X$t{0};
51Testing软件测试网 P]pK-o#b

Y b y)Di O4})HWL0int main(int argc, const char * argv[])
2o7f \'iuFE[0{
4paVaTv|;] i0    iiostream oo;51Testing软件测试网M#u:Lz\SQwW
51Testing软件测试网 ka] b~XV5uY

U._W7~vS0X/o0  其输出结果为:51Testing软件测试网'aTH+Ao:m

D`{3gmg8vT"e#J0  stream::stream()!
I:@oZ#Zw0rD0  istream::istream()!51Testing软件测试网i2|^;Rr+J]
  stream::stream()!51Testing软件测试网!f.i"qe[ U;cP?L
  ostream::ostream()!
V^f%L(wP m*~],J0  iiostream::iiostream()!

X6O `l+uHwK0

u(@1|%q[l$t-yG0  从结果可以看到,其构造过程中重复出现基类stream的构造过程。这样就完全没有达到虚拟继承的目的。其继承结构为:51Testing软件测试网R Y!C$AB0@$P8J

51Testing软件测试网5t` CA)E#l

  stream              stream
p;G:M ]$`h5e0  \                     /
3n.DS h6h*e6k6xq[0  istream    ostream51Testing软件测试网+n I-|-Ji?X
  \                   /
;~!^#yk}[u+_-X0  iiostream
51Testing软件测试网/i,H-^:n)G1E#L/K

51Testing软件测试网#\.S&Si$u"K dn/K

  从继承结构可以看出,如果iiostream对象调用基类stream中的成员方法,会导致方法的二义性。因为iiostream含有指向其虚 继承基类 istream,ostream的vptr。而 istream,ostream包含了stream的空间,所以导致iiostream不知道导致是调用那个stream的方法。要解决改问题,可以指定 vptr,即在调用成员方法是需要加上作用域,例如51Testing软件测试网2e`N0a R#fP,M

y o%z W+Z"w#d w051Testing软件测试网"Xm/y1tyq{;nY g v'T

class stream
0TQVT)@N}N0{
zh k5P,`'\0   void f(){cout<<"here!"<<endl;}51Testing软件测试网 u%`"w%H$O5cvW

V};}`'CsY0`'EO0main()51Testing软件测试网u.y!NXE5L }3nV
{51Testing软件测试网RJH$F;`%_"S
  iiostream ii;51Testing软件测试网9_f3oYu%R
  ii.f();51Testing软件测试网5v }#Z-_yvo
}

TAG:

 

评分:0

我来说两句

Open Toolbar