1、在大多数情况下,当一个对象出现并开始工作的时候,它就能够执行我们需要它做的事情,因为它的能力在其接口中已经被明确的通告了。在这些情形下,不需要询问该对象是否胜任我们要它执行的工作,只管叫它去做就行了:
class Shape {
public:
virtual ~Shape( );
virtual void draw( ) const = 0;
//....
};
//....
Shape *s = getSomeShape( ); //获得一个Shape,并且叫它去做...
s->draw( ); //干活
即使不知道所面对的形状的精确类型,我们也知道该对象”是一个“Shape,因此它可以绘制自身。这很高效且简单。
有时一个对象具备出来准备工作的能力,但它的能力并非那么显而易见。
例如,我们需要一些可以滚动的形状:
class Rollable {
public:
virtual ~Rollable( );
virtual void roll( ) = 0;
};
像Rollable这样的类通常称为“接口类”。因为它只指定了接口,如同java接口一样。
通常来说,这样的类没有非静态成员数据成员,没有声明构造函数。
一个虚析构函数和一个(或一组)纯虚函数指明了一个Rollable对象能够做什么。
2、不幸的是,我们偶尔会不知道一个对象是否具有所需能力。在这种情况下,我们被迫执行一个能力查询。
在c++中能力查询是通过对“不相关”的类型进行dynamic_cast转换而表达的。
Shape *s = getSmoeShape( );
Rollable *roller = dynamic_cast<Rollable *> (s);
这种dynamic_cast用法通常称为“横向转型”。
因为它试图在一个类层次结构中执行横向转换,而不是向上或向下转换。
如果s实际指向的是一个Shape,那么dynamic_cast将会失败(结果产生一个空指针),从而知道s所指向的Shape不是Rollable。如果s指向的是一个Circle或从Rollable派送下来的其他Shape,那么转型会成功,从而得知可以滚动这个形状。
Shape *s = getSomeShape( );
if( Rollable *roller = dynamic_cast<Rollable *> (s) )
roller->roll( );
3、能力查询只是偶尔需要。
除非身陷找不到其他合理方式的困境,否则最好避免对一个对象的能力进行运行期查询。