协变返回类型

  一般来说,一个重写的函数与被它重写的函数必须具有相同的返回类型:

Class Shape {
Public:
//…
Virtual double area () const = 0;
//…
};
Class Circle : public Shape {
 Public:
       //…
       Float area () const ; //错误!返回类型不同
       //…
};
 
然而,这个规则对于”协变返回类型(covariant return type)”的情形来说有所放松.也就是说,若B是一个类类型,并且一个基类虚拟函数返回B *,那么一个重写的派生类函数可以返回D *,其中的D公有派生于B(即D是一个(is-a)B).若基类虚函数返回B &,那么一个重写的派生类函数可以返回一个D&.考虑如下一个shape层次结构的clone操作:
Class Shape {
Public:
//…
Virtual Shape *clone () const = 0; //prototype(原型)
//…
};
Class Circle : public Shape {
 Public:
       //…
       Circle *clone () const ;
       //…
};
  重写的派生类函数被声明为返回一个Circle *而不是一个Shape *.这是合法的,因为Circle是一个Shape.注意如一个CIrcle被当作Shape进行操作,从返回的Circle *就回被自动转化为Shape *:
   Shape *s1 = getACircleOrOtherShape ();
Shape *s2 = s1->clone();
 
当直接操纵派生类型而不是通过其基类接口来操纵它们时,使用协变返回类型的优势就会体现出来了:
 Circle *c1 = getACircle();
 Circle 8c2 = c1->clone();
 如果没有协变返回机制,Circle::clone将不得不精确的匹配Shape::clone的返回类型,从而返回一个Shape *.我们就被迫将返回结果转换为Circle *.
 Circle *c1 = getACircle();
 Circle *c2 = static_cast<Ciecle *>( c1->clone());
 
 再看另外一个例子。考虑如下Shape的Factory Method成员,它返回一个引用,指向与具体的形状对应的形状编辑器:
Class ShapeEditor {……};
Class Shape {
     Public:
         //…
          virtual const ShapeEditor & getEditor () const = 0; //Factory Method
         //…
};
//….
Class Circle;
Class CircleEditor : public ShapeEditor { … };
Class Circle : Public Shape{
     Public:
         Const CircleEditor &getEditor () const ;
     //…
};
 在这个例子中,注意CircleEditor必须在Circle::getEditor的声明之前被完整地定义(而不能仅仅声明)。因为编译器必须知道CircleEditor对象的布局,才能执行适当的地址操纵,从而将一个CircleEditor引用(或指针)转换为一个ShapeEditor引用(或指针)。
 
 协变返回类型的优势在于,总是可以在适当程度的抽象层面工作。若我们是处理Shape,将获得一个抽象的ShapeEditor;若正在处理某种具体的形状类型,比如Circle,我们就可以直接获得CiecleEditor.协变返回机制将我们从这样的一种处境解脱出来:不得不使用易于出错的转换操作来“重新”提供类型信息,而这种信息是一开始就不应该丢掉的:
Shape * s = getACircleOrOtherShape ();
Const ShapeEditor &sed = s->getEditor();
Ciecle *c =getACircle();
Const CircleEditor &ced = c->getEditor();

你可能感兴趣的:(协变返回类型)