您的位置:首页 > 编程语言 > C语言/C++

C++必知必会之(31)协变返回类型

2013-12-12 10:45 204 查看
1、一般来说,一个重写的函数必须与被他重写的函数具有相同的返回类型:

class Shape {

public:

//....

virtual double area( ) const = 0;

//...

};

class Circle : public Shape {

public:

float area( ) const; //错误,返回类型不同

//....

};

然而, 这个规则对于“协变返回类型”的情形来说显得不那么严格。

也就是说,如果B是一个类类型,并且一个基类虚函数返回B*,那么一个重写的派生类函数可以返回D*,其中的D公有派生于B(即D是一个(is-a)B)。如果基类虚函数返回B&,那么一个重写的派生类函数可以返回一个D&。

考虑如下这个Shape层次结构的clone操作:

class Shape {

public:

//....

virtual Shape *clone( ) const = 0; //原型

//...

};

class Circle : public Shape {

public:

Circle *clone( ) const;

//...

};

重写的派生类函数被声明为返回一个Circle*而不是一个Shape*。

这是合法的,因为CIecle是一个Shape。注意,如果一个Circle被当作Shape进行操纵,从Circle::clone返回的Circle*机会被自动转换为Shape*。

Shape* s1 = getACircleOrOtherShape( );

Shape* s2 = s1->clone( );

当直接操纵派生类型而不是通过其基类接口来操纵它们时,使用协变返回类型的优势就体现出来了:

Circle *c1 = getACircle( );

Circle *c2 = c1->clone( );

如果没有协变返回机制,Circle::clone将不得不精确地匹配Shape::clone的返回类型,从而返回一个Shanpe*。我们就被迫将返回结果转型为Circle*。

Circle *c1 = getACircle( );

Circle *c2 = static_cast< Circle *>( c1->clone( ) );

2、再看另一个例子。

考虑如下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引用(或指针)。

3、协变返回类型的优势在于,总是可以在适当的抽象层面工作。

如果我们是在处理Shape,将获得一个抽象的ShapeEditor;如果正在处理某种具体的形状类型,比如Circle,我们就可以直接获得CircleEditir。

协变返回机制将我们从这样的一种困境解脱处理,那就是不得不使用易于出错的转型操作来“重新”提供类型信息,而这种信息是一开始就不应该丢掉的:

Shape *s = getACircleOrOtherShape( );

const ShapeEditor &sed = s->getEditor( );

Circle *c = getACircle( );

const CircleEditor &ced = c->getEditor( );
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: