返祖是生物乃至人类的一种遗传缺陷,是祖先遗传基因的突显。其实生物乃至人类的基因中本来就存在有祖先的基因成分,只是正常情况下被隐藏在深处而已。
在前面讲述类的成员函数覆盖时,曾经说过被覆盖的成员函数在当前类和所有派生类中将不再呈现出来。但不呈现不等于消失了,只是被后辈的相关特性(成员函数)给覆盖了。那么在C++中类似的“返祖”可否实现,其用处又在那里?从下面的例子中可见一斑。先列出程序如下:
class point { protected: int x, y;
public: point( int x0, int y0 ) { x = x0; y = y0; } void Display( void ); };
void point::Display( void ) { // display a point, 坐标为(x,y) }
class line : public point { protected: int r, d;
public: line( int x0, int y0, int r0, int d0 ) : point( x0, y0 ) { r = r0; d = d0; } void Display( void ); };
void line::Display( void ) { // display a line, 以(x,y)为一点,长度为r,角度为d }
class circle : public line { public: circle( int x0, int y0, int r0 ) : line( x0, y0, r0, 0 ) {} void Display( void ); };
void circle::Display( void ) { // display a circle,以(x,y)为圆心,r为半径 }
circle C(0, 0, 10);
int main( void ) { C.Display(); while ( 1 ) { } }
上叙程序中定义了三个类,分别是:point,line和circle。其中由point派生line,再由line派生circle。它们都有一个成员函数Display()。由于存在上面的继承关系,所以派生类的Display()覆盖了基类的Display()。这样一来可以看到,最终对象C中的显示功能(C.Displya())是显示一个以原点(0,0)为圆心以10为半径的圆。如果要想利用对象C来显示其半径或圆心(这是CAD中经常遇到的事情)是否有可能呢?答案是肯定的。下面给出两种实现方法:
一,作用域指定
C.line::Display(); C.point::Display();
利用作用域符“::”直接改变类的作用域(只能向基类方向改),使C原先被覆盖的显示功能呈现出来。
二,利用函数返祖
void Display_line( line& L ) { L.Display(); }
void Display_point( point& P ) { P.Display(); }
上面是增加的两个附加函数。它们的参数分别是以circle的两个基类为引用类型,因此一旦进入到函数体内对象就将呈现出其祖先的面貌,所以其显示功能就具有了返祖的特性。下面是具体的两个函数的调用语句:
Display_line( C ); Display_point( C );
它们同样分别显示了圆的半径和圆心。
最后要提醒的是,对于虚函数,上述两种方法结果不一样(具体以后再表)。所以这两钟方法不是完全等价的。 |