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( );
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( );
相关文章推荐
- 返回类型协变
- 协变、逆变与不变:数组、泛型、与返回类型
- 【JavaSE】协变返回类型
- 第八章 多态总结 协变返回类型 向下转型 和运行时类型识别继承中 is-a 和 is-like-a及子类父类的方法调用(ClassCastException)
- Java之协变返回类型理解和简单实例
- 理解Java中的协变返回类型
- 编程思想 之「多态、初始化顺序、协变返回类型」
- C++ 返回类型协变
- Java协变返回类型
- java学习笔记---协变返回类型
- java编程思想--协变返回类型
- 关于java可变(协变)返回类型的解说之一------------基类与派生类
- 协变返回类型
- Java | 协变返回类型学习时的一个例子
- C++基础::语法特性::函数重写(override)与协变返回类型(covariant return type)
- 给定一个整数(字符串也适用)序列,重新排列,得到最大的结果,比如31,3,35,7,9根据排列后得到组合 9735331,返回的是string类型
- java中的协变返回类型
- 协变返回类型
- Covariant Returen Types(协变返回类型)
- 协变返回类型