我今天遇到了一个问题found here,它为我提出了这个问题。
这是我所得到的伪代码示例:
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
仅在单个 vector 中跟踪其Cars
。由于他的Cars
太多,因此很难根据它们是FordFocus
还是Lamborghini
来跟踪它们。但是,他唯一具有可伸缩车顶的汽车是Lambo。为了retractTheRoof()
,RichGuy
现在必须确定他拥有的Car
是否确实是Lamboghini
,然后向下转换以执行此功能。根据此示例,是否选择精打细算?还是它违反了多态性的目的,假设目的是允许派生类定义自己的行为,并为
RichGuy
等类提供通用接口(interface)?如果是这样,是否有更好的方法允许retractTheRoof()
使用类似RichGuy
的功能(或至少它的作用)? 最佳答案
现在,如果有多种类型的可伸缩汽车,比如说这些汽车是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();
}
因此,在这种情况下,更好的设计是:添加一个名为
IRetractable
的接口(interface)并从中派生: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
,但是此处的要点是,您只在使用接口(interface),而无需在任何地方提及具体的类。换句话说,设计仍然尽可能多地使用运行时多态。这是Design Patterns的原理之一:另外,请参阅以下内容:
另一个重要的一点是,必须将
Car
(基类)的析构函数设为虚拟:class Car{
public:
virtual ~Car() {} //important : virtual destructor
virtual int goFast() = 0;
};
这很重要,因为您要维护
Car*
的 vector ,这意味着以后您想通过基类指针删除实例,为此您需要使~Car()
成为虚拟析构函数,否则delete car[i]
会调用未定义的行为。