Ann*_*inn 17 c++ oop polymorphism
我今天在这里找到了一个问题,它为我提出了这个问题.
这是我所得到的伪代码示例:
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();
};
};
};
Run Code Online (Sandbox Code Playgroud)
在示例中,有一个RichGuy类. Richguy只Cars在一个向量中跟踪他.因为他有这么多Cars,所以根据他们是一个FordFocus还是一个来跟踪它们会很麻烦Lamborghini.然而,他有一个可伸缩屋顶的唯一类型的汽车是兰博.为了retractTheRoof(),RichGuy现在必须确定Car他是否确实是一个Lamboghini,然后向下转发执行它的这个功能.
基于这个例子,是否选择了良好的设计?或者它是否违反了多态的目的,假设目的是允许派生类定义自己的行为,并为类提供通用接口RichGuy?如果是这样,是否有更好的方法可以使用retractTheRoof()(或至少它的效果)等功能RichGuy?
Naw*_*waz 14
现在,如果有不止一种类型的汽车是可伸缩的,说这样的车CarA,CarB和CarC(除Lamborghini),那么你要这样写:
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();
}
Run Code Online (Sandbox Code Playgroud)
因此,在这种情况下更好的设计是:添加一个名为的接口IRetractable并从中派生出来:
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 {
//...
};
Run Code Online (Sandbox Code Playgroud)
然后你可以简单地写这个:
if(IRetractable *retractable = dynamic_cast<IRetractable *>(cars[i]))
{
retractable->retractTheRoof(); //Call polymorphically!
}
Run Code Online (Sandbox Code Playgroud)
凉?不是吗?
在线演示:http://www.ideone.com/1vVId
当然,这仍然使用dynamic_cast,但重要的一点是你只使用接口,无需在任何地方提及具体类.换句话说,设计仍然尽可能地使用运行时多态性.这是设计模式的原则之一:
"编程到'界面',而不是'实现'." (Gang of Four 1995:18)
另外,看到这个:
其他重要的一点是你必须使Car(基类)虚拟的析构函数:
class Car{
public:
virtual ~Car() {} //important : virtual destructor
virtual int goFast() = 0;
};
Run Code Online (Sandbox Code Playgroud)
它很重要,因为你正在维护一个向量Car*,这意味着,稍后你想通过基类指针删除实例,你需要为它做~Car()一个虚拟析构函数,否则delete car[i]会调用未定义的行为.
是的,这通常是更好的设计案例.如果对所有派生类都有意义,则只应在层次结构中引入虚函数.
但是,你的MODEL枚举完全没有价值 - 这dynamic_cast就是实际的目的.
if(Lamborghini* lambo = dynamic_cast<Lamborghini*>(cars[i])) {
lambo->retractTheRoof();
}
Run Code Online (Sandbox Code Playgroud)