C++之能力查询

      在大多数情况下,当一个对象出现并开始工作时,它就能够执行我们需要它执行的事情,因为它的能力已经在接口中被明确的定义好了。

class Shape {

   public:

    virtual ~Shape();

    virtual void draw() const = 0;

    // ....

};

//````

Shape* s = getSomeShape();    // 获得一个shape,并且叫它去.... 

s->draw();  // 干活....

     这样,我们只管叫这个对象去干活就行了。这很简单,也很高效,正是我们想要的效果。

     然而,在实际中并非一切都是这么顺理成章,很多时候我们需要知道(或者测试)一个对象具备什么样的能力。

例如,对于上面的例子我们可能需要一些能够滚动的形状。那么我们写一个Rollable类,然后让具体的Shape类(例如下面的Circle类)多重继承自Shape和Rollable。

class Rollable{

    public:

     virtual ~Rollable();

     virtual void roll() = 0;

};

像这样的类通常是一个接口类(interface class),因为它只指定了接口,如同Java的接口一样。通常来说,这样的类没有非静态成员,没有声明构造函数。一个虚析构函数和一个纯虚函数指明了一个Rollable对象能够做什么。

class Circle : public Shape, public Rollable {    // 多重继承,圆形可以滚动

   public:

    //```

     void draw() const;

      void roll();

};

    当然,并不是所有的Shape类对象都可以滚动

class Square : public Shape {   //  单继承,正方形不能滚动

   //...

   void draw() const;

};

也有一些能滚动的对象却不是一个(not is-a)Shape.

class Wheel : public Rollable {

     // ....
};

     在我们试图滚动某一个对象之前,我们总是想知道面对的对象是否为Rollable,但是我们并不总是知道这样的对象是否具有这样的能力。在这种情况下,我们需要执行一个能力查询(测试)。在C++中能力查询通常是通过对“不相关”的类型进行dynamic_cast 转换而表达的。

Shape *s = getSomeShape();

Rollable *Roller = dynamic_cast<Rollable*>(s);

      这种 dynamic_cast 用法通常称为“横向转型(cross-cast)”,因为它试图在一个类层次结构中执行横向转换,而不是向上或者向下转换。

如果查询成功比如说s实际指向的是圆(或者派生自Rollable的其它Shape),那么转型成功,Roller指向该对象。如果s实际指向的对象是一个Square(或者其它的未派生自Rollable的Shape), dynamic_cast 就会失败(结果返回一个空指针)。

所以可以用以下的代码来进行判断控制。

if ( Rollable *Roller = dynamic_cast<Rollable*>(s) )

             roller->roll();

能力查询只是偶尔需要,但它们往往被过度使用。它们通常是糟糕设计的“指示器”。

 

参考:《C++必知必会》P72 条款27 能力查询

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值