C++ 虚继承与继承的差异

上一篇 / 下一篇  2012-10-10 13:58:44 / 个人分类:C++

%K\\vZH3?2E2V0  前面一篇文章,说明了在C++ 虚继承对基类构造函数调用顺序的影响。经过仔细推敲,发现没有彻底说清楚虚继承与普通继承之间的关系。所以用下面的文字再说明一下。51Testing软件测试网/A4S'v$EA:pi(O

)N.iC x#I@@ kY0  首先,重复一下虚拟继承与普通继承的区别有:

:sTB#g.d A0

bap0?KD[f:@7F*x0  假设derived 继承自base类,那么derived与base是一种“is a”的关系,即derived类是base类,而反之错误;51Testing软件测试网Y)b d:A~ ^

#r(B(U7w~1J m q0  假设derived 虚继承自base类,那么derivd与base是一种“has a”的关系,即derived类有一个指向base类的vptr。

R8i4I[X[0[hx051Testing软件测试网s:^vx!M R

  因此虚继承可以认为不是一种继承关系,而可以认为是一种组合的关系。因为虚继承有着“继承”两个关键字,那么大部分人都认为虚继承与普通继承的用法没什么太大的不同。由此用在继承体系中,这种将虚继承认为是普通继承的危害更佳大。下面先用一个例子来说明问题:51Testing软件测试网'Yv(`.I6A3`

z6_7neR0class base
2a/L;}y ]/L~_*m0{
'T!`:ay:ikzu0public:51Testing软件测试网\ eQdI |E
    base(){cout<<"base::base()!"<<endl;}51Testing软件测试网a-n2Yo1Qc#FAX
    void printBase(){cout<<"base::printBase()!"<<endl;}51Testing软件测试网9Y x&J7^?0^7v b
};
51Testing软件测试网kTV#qwC

51Testing软件测试网/~pl&R Rj

class derived:public base
x9m-W0Q_2^B0{51Testing软件测试网M,U4Aj"S7CN [
public:
g\#y-P~,~ _-f?0    derived(){cout<<"derived::derived()!"<<endl;}51Testing软件测试网*[%K8w)|8g_3Z/b
    void printDerived(){cout<<"derived::printDerived()!"<<endl;}
/|L:n9T2l,Z]i0};

!mQ%G$q"YAGp0

I%o4aw'l M/AAy0  上面是普通继承实现,在实际应用中,我们可以使用下面的代码进行类型转换:51Testing软件测试网`}z!T s1Q l,u

int main(int argc, const char * argv[])51Testing软件测试网I1v mfp3j)Oc[
{
aC j#Zv2rT0    derived oo;51Testing软件测试网 @ Q2K+Q V&{t
    base oo1(static_cast<base>(oo));51Testing软件测试网(\,q?ojp bG9G {5u]^sl
    oo1.printBase();
d?7?-YHd D-T0    derived oo2 = static_cast<derived&>(oo1);
1l C wY#B&D J&g/^by'{0    oo2.printDerived();51Testing软件测试网E%{h2S)WH;_8q
    return 0;51Testing软件测试网d$X/I$hJ
}
51Testing软件测试网i.cH? [)N1E

  编译无错误,而且会得出正确的结果。其结果为:51Testing软件测试网FIq3d%iVVuY3k

51Testing软件测试网 _3pl3`3VAJ0FB!^

  base::base()!51Testing软件测试网 bU5}w g~#S m
  derived::derived()!51Testing软件测试网[3}!Lr{W&pj
  base::printBase()!
7j ^&tyb0  derived::printDerived()!
51Testing软件测试网3rP8dx(X Gg*Np0]

51Testing软件测试网.?o D!U&b5s}%\

  而将上面的普通继承变成虚拟继承,如下代码:51Testing软件测试网pNWO8ux0M

7U-U4F Y*E0class base1
H*V\;\r0NL X0{51Testing软件测试网!v z@ z$[l"x1J
public:51Testing软件测试网-x:c h%f3x,A,M
    base1(){cout<<"base::base()!"<<endl;}51Testing软件测试网ts@'` J
    void printBase(){cout<<"base::printBase()!"<<endl;}
~P b{jTw0};
51Testing软件测试网x(C"c4T:D.o$N1@

51Testing软件测试网YFE k S'Fh1N

class derived1:virtual public base1
%Y0O~CuUi;m%h0{
-R#v4XQ%{"j[U0public:51Testing软件测试网b^~!h}.i
    derived1(){cout<<"derived::derived()!"<<endl;}51Testing软件测试网Yu)\ h*`;z Y:b4Cd&[
    void printDerived(){cout<<"derived::printDerived()!"<<endl;}
/f1x4c!x1Y9k}$M;j0};

/h j4UV)Z0

7U x6?2Y$ub.?/e*M0int main(int argc, const char * argv[])
h_1t t'xX0{51Testing软件测试网 H,J {w M6Y s/m
    derived1 oo;51Testing软件测试网8u*o-v3R?(P
    base1 oo1(static_cast<base1>(oo));51Testing软件测试网5M3X5j7Z{g|"q I
    oo1.printBase();51Testing软件测试网] VKoq-L!a)c{
    derived1 oo2 = static_cast<derived1&>(oo1);51Testing软件测试网+JwI\]
    oo2.printDerived();
:P K!Q X(I6U V:NX}9DX0    return 0;51Testing软件测试网!LLt4~y@(wBJu
}
51Testing软件测试网8NKB9Q)x.]s n

] _4B9jk@0  编译上面的代码,提示如下:51Testing软件测试网d"`4S[ |8B}

51Testing软件测试网w r$kj]As bI

  可以看到不能将基类通过static_cast转换为继承类。我们知道c++提供的强制转换函数static_cast对于继承体系中的类对象的转换一般是可行的。那么这里为什么就不可以了呢?还是需要从虚拟继承的内部实现来说明问题。

a!VP#Q2jLX0

   virtual base class的原始模型是在class object中为每一个有关联的virtual base class加上一个指针vptr,该指针指向virtual基类表。有的编译器是在继承类已存在的virtual table直接扩充导入一个virtual base class table。不管怎么样由于虚继承已完全破坏了继承体系,不能按照平常的继承体系来进行类型转换。51Testing软件测试网{_l H`

  不管怎么样,虚继承在类型转换是一定要十分注意。不要轻易使用虚继承,更不要在虚继承的基础上进行类型转换,切记切记!

!we {8lS N?0

TAG:

 

评分:0

我来说两句

Open Toolbar