C++ 继承机制易犯的错误
上一篇 /
下一篇 2012-09-21 09:22:19
/ 个人分类:C++
51Testing软件测试网 Q'}2Rlt'x4|3B 继承作为面向对象的基本特征之一,其使用率极高。不管是为了实现软件的基本功能,还是再程序的重构的过程中,我们总是会用到继承机制。正是因为
其用途极为广泛,而且使用简单,大众程序员对其真正的内部实现机制的探究不是很深。而且,在大部分情况下,我们对继承的使用方法是错误的。下面用例子来说
明问题。
|"_rRF.\0
51Testing软件测试网GF&R?
L
51Testing软件测试网8U\{)Kb4\;`J*O
class Animal {51Testing软件测试网}5r Ps-q7P'] public: ~#luCc,`Aj)e0 Animal &operator=(const Animal &rhs); HF8bZ1P0 ... `3G9Ph!]V0}; A5W:bt;Vp jI
mm0class Animal1: public Animal { 1p%t9a
n-_ ~_q0 public:51Testing软件测试网K*aPC r?}f Animal1 &operator=(const Animal1 &rhs);51Testing软件测试网kq`,Y8S5a U2Q![H ... 8^p)aPL9xc3OE!z0}; '`?2w2h
g*gs)w)pA0class Animal2: public Animal {51Testing软件测试网u Nsl_7Wec/d&Q public:51Testing软件测试网4f6IY oB2IVom4J Animal2 &operator=(const Animal2 &rhs);51Testing软件测试网|7]TnaaNo0M ...51Testing软件测试网 V!CrE?"rvW }; |
K?syj0k.spuR0 上面的代码只是简单的定义一个继承体系,即Animal作为基类,Animal1和Animal2公共继承它。三者都重载了赋值运算符。这对于问题的说明已经足够了。考虑下面的代码:51Testing软件测试网G$W OaU&eoz"k$Tv
51Testing软件测试网9_${ |e-C!~
51Testing软件测试网'Ek/g.?2c7V(T
Animal1 an1; |[+u$GgF
Q0Animal1 an2; "Fw/ufa9N
f] @A0Animal *pAn1 = &an1;51Testing软件测试网*KH5q2\2V Animal *pAn2 = &an2;51Testing软件测试网.@Q U%l I$G!N
^ ... cN(I2t8~[ O#C0*pAn1 = *pAn2; |
Sw
U.ns p0 上面的代码足够简单了吧!问题就出现了。我们在最后一行的目的是将an2赋值给an1.如果你不是此目的,那么可以绕开本文了!因为通过指针,
对对象进行赋值动作对于c++程序员来说,非常普遍。但是实际的效果确是,an1的Animal成分与an2的Animal成分相同,而an1的
Animal1成本保持不变。这里提一下出现这种情况的原因:1、继承体系中的赋值函数是重载,而不是覆盖和隐藏(注意三者的区别:);2、由于
Animal *pAn1 =
&an1,是产生pAn1所覆盖的范围缩小的效果,因此当采用赋值操作时,实际上调用的赋值函数时基类的赋值函数。这种效果是不是导致你的an1
对象二不象了,既不是原来的an1对x爱嗯,也不是你期待的an2对象。不过,如果你是想达到这种移花接木的效果,那么我恭喜你,这种用法太妙了,也说明
你对c++ 的继承体系已经到了一种登峰造极的地步。51Testing软件测试网5Gp\q(pkNo
51Testing软件测试网Sg4?_5W k"\b 不过,大部分人都不是实现移花接木的功能,那么怎么实现全部成分的赋值效果呢?51Testing软件测试网zDfm;R
g oLV;j qu
51Testing软件测试网 V)E3[/O:P_\T 既然已经用到了继承机制,那么就不得离开虚函数了。我们将赋值操作符函数定义为虚函数,代码如下:
L["D9~2C#?kb0
S0M}}
\,B~0
z7Y7Cy'p4p0
class Animal {51Testing软件测试网T6x K;OuJ public: ;{4T1f:S!I0 virtual Animal &operator=(const Animal &rhs);51Testing软件测试网)?h/DGZ ...51Testing软件测试网
H/q]J{0qz.]6rO }; 5E+VnEH"z NqL0class Animal1: public Animal {51Testing软件测试网K{V0J.ge public:51Testing软件测试网!Ciy^1\ virtual Animal1 &operator=(const Animal1 &rhs); -S`:R/`$T-Zsl*n0 ...};class Animal2: public Animal { public: virtual Animal2 &operator=(const Animal2 &rhs);51Testing软件测试网s2x1z+@Z
@ ...}; |
0n8^E6^l#rw;B0 采用虚函数确实能够解决上面提到的全部成分的赋值效果,因为他会导致覆盖赋值函数,而不是上面的重载,因此会调用实际Animal1类的赋值函数。但这样仍然会带来问题,如下的代码:
&]'Fe F7v-S.w^0
T4[8} b~0
7T+o-W}%?
|#p0
Animal1 an1; ]\ ZS!ujO`0Animal2 an2;//这里是Animal2对象,与前面的Animal1不同 )s:m^;^A0Animal *pAn1 = &an1; g3o;z%WP0Animal *pAn2 = &an2; 9p/aA
T/kG0... aEfvh4z0\0*pAn1 = *pAn2;//将Animal2对象赋值给Animal1 |
51Testing软件测试网'y)h"E~%N"u#X 这样子会允许异型转换,明显还是会出现问题。如何解决呢?可以参考《More Effective c++》里面的条款34。
c[{ s)n-z
l
EPs0
收藏
举报
TAG: