downcasting是否失败了多态性的目的? [英] Does downcasting defeat the purpose of polymorphism?

查看:168
本文介绍了downcasting是否失败了多态性的目的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我今天遇到了一个问题,在这里找到,为我提出这个问题。

I encountered a question today, found here, which raised this question for me.

这是一个伪代码示例,我得到的是:

Here's a pseudo-code example of what I'm getting at:

class Car{
public:
    virtual int goFast() = 0;
};


class FordFocus : public Car {
public:
    int goFast(){
        return 35;
    };
};


class Lamborghini : public Car {
    bool roof;
public:
    int goFast(){
        return -1/0;  // crash 
    };
    void retractTheRoof(){
        roof = 0;
    };
};



class RichGuy {
    vector<Car *> cars;
public:
    void goDrive() {

        for(int i = 0; i < cars.size(); ++i) {
            if(Lamborghini* lambo = dynamic_cast<Lamborghini*>(cars[i])) {
                lambo->retractTheRoof();
            };
            goFast();
        };
    };
};

在示例中,有一个 RichGuy 类。 Richguy 只在一​​个向量中跟踪他的 Cars 。因为他有这么多 Cars ,根据他们是 FordFocus 来跟踪他们太麻烦了,或 Lamborghini 。然而,他只有一种类型的汽车,他有一个可伸缩的屋顶是兰博。为了 retractTheRoof() RichGuy 现在必须确定 Car 他确实是一个 Lamboghini ,然后downcast执行它的这个功能。

In the example, there is a RichGuy class. Richguy only keeps track of his Cars in a single vector. Because he has so many Cars it would be too troublesome to keep track of them based on if they're a FordFocus or a Lamborghini. However, the only type of car he has with a retractable roof is the Lambo. In order to retractTheRoof(), RichGuy must now determine if the Car he has is indeed a Lamboghini, and then downcast to execute this function of it.

基于这个例子,是在良好的设计downcast的选择?或者它违反了多态性的目的,假设目的是允许派生类定义自己的行为,并为类如 RichGuy 提供一个通用接口?如果是这样,是否有更好的方法允许 retractTheRoof()(或至少它的效果)可用于 RichGuy 使用?

Based on this example, was the choice to downcast in good design? Or did it violate the purpose of polymorphism, assuming that purpose is to allow derived classes to define their own behavior, and provide a common interface for classes like RichGuy? And if so, is there a better way to allow for functions like retractTheRoof() (or at least it's effect) to be available to RichGuy to use?

推荐答案

现在如果有多种类型的汽车可伸缩,是 CarA CarB CarC Lamborghini ),那么你要这样写:

Now if there are more than one type of cars which is retractable, say such cars are CarA, CarB, and CarC (in addition to Lamborghini), then are you going to write this:

if(Lamborghini* lambo = dynamic_cast<Lamborghini*>(cars[i])) {
    lambo->retractTheRoof();
}
else if(CarA * pCarA = dynamic_cast<CarA*>(cars[i])) {
    pCarA->retractTheRoof();
}
else if(CarB * pCarB = dynamic_cast<CarB*>(cars[i])) {
    pCarB->retractTheRoof();
}
else if(CarC * pCarC = dynamic_cast<CarC*>(cars[i])) {
    pCarC->retractTheRoof();
}

因此,在这种情况下更好的设计是: code> IRetractable 并派生自它:

So a better design in such cases would be this: add an interface called IRetractable and derive from it as well:

struct IRetractable 
{
   virtual void retractTheRoof() = 0;
};

class Lamborghini : public Car, public IRetractable {
   //...
};

class CarA : public Car, public IRetractable {
   //...
};
class CarB : public Car, public IRetractable { 
   //...
};
class CarC : public Car, public IRetractable {
   //...
}; 

那么你可以这样写:

if(IRetractable *retractable =  dynamic_cast<IRetractable *>(cars[i])) 
{
    retractable->retractTheRoof(); //Call polymorphically!
}

酷?不是吗?

在线演示: http://www.ideone.com / 1vVId

当然,这仍然使用 dynamic_cast ,但 / strong>这里是您只使用接口,无需在任何地方提及具体类。换句话说,设计仍然尽可能多地使用运行时多态性。这是设计模式的原则之一:

Of course, this still uses dynamic_cast, but the important point here is that you're playing with interfaces only, no need to mention concrete class anywhere. In other words, the design still makes use of runtime-polymorphism as much as possible. This is one of the principle of Design Patterns:


编程到一个'接口',而不是一个'实现'。 (Gang of Four 1995:18)

"Program to an 'interface', not an 'implementation'." (Gang of Four 1995:18)

此外,请参阅:

  • What does it mean to "program to an interface"?

其他重要的一点是你必须使 Car (基类)的析构函数:

Other important point is that you must make the destructor of Car (base class) virtual:

class Car{
public:
    virtual ~Car() {} //important : virtual destructor
    virtual int goFast() = 0;
};

它的重要性,因为你维护一个 Car * ,这意味着,以后你想通过基类指针删除实例,你需要使〜Car()一个虚拟析构函数,否则 delete car [i] 会调用未定义的行为。

Its imporant because you're maintaining a vector of Car*, that means, later on you would like to delete the instances through the base class pointer, for which you need to make ~Car() a virtual destructor, otherwise delete car[i] would invoke undefined behaviour.

这篇关于downcasting是否失败了多态性的目的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆