说我有类似的东西 - 这只是一个关注你的例子。
class Car
{
void accelerate();
void stop();
}
class Person
{
void drive(Car car);
}
class Toyota : public Car
{
void accelerateUncontrollably();
}
class ToyotaDriver : public Person
{
void drive(Car car)
{
// How to accelerateUncontrollably without dynamic cast?
}
}
有几件事,丰田汽车和ToyotaDriver会在一起,即我可以有一个ToyotaFactory
课程,它将返回司机和汽车。因此,这些部件可以互换并用于代码的不同部分,但丰田和ToyotaDriver一起使用。
答案 0 :(得分:3)
你不能也不应该......
这是为了保护你自己:)
加速控制只能在丰田车上完成(但不能在其他车型中完成)然后定义是可以的,你应该首先检查汽车是否真的是丰田汽车或所有汽车都可以“加速不可控制地”然后宣告应该在Car类中。
当然,你可以做一个演员......但是问问自己......如果你确实知道你得到的子类型......为什么你收到一辆车而不是丰田?
编辑:我仍然不明白为什么你不能编辑它看起来像:
interface IToyotaAccelerable
{
void accelerateUncontrollably();
}
class Toyota : public Car : IToyotaAccelerable
{
void accelerateUncontrollably();
}
class ToyotaDriver : public Person
{
void drive(Car car)
{
// Do whatever logic you want with the car...
// How to accelerateUncontrollably without dynamic cast?
IToyotaAccelerable accel = car as IToyotaAccelerable
if (car != null)
{
accel.accelerateUncontrollably();
}
}
}
现在你正在针对一个行为属性进行编程,某个给定的对象可以或不可以...所以你不需要强制转换,而且至少从一个语义角度来看,函数更有意义图强> ...
答案 1 :(得分:3)
您可以通过以下简单的委托方式委托来避免不雅观downcasting并打破Liskov Substitution Principle:
class Toyota : public Car
{
void accelerateUncontrollably() // can't have abstract methods here, btw
{
// throttle the engine unexpectedly, lock pedal beneath mat, etc.
}
void accelerate() // you have to implement accelerate anyway because of Car
{
accelerateUncontrollably();
}
}
现在,ToyataDriver将不知道简单地加速会无法控制地加速:
class ToyotaDriver : public Person
{
void drive(Car car)
{
car.accelerate();
}
}
另请注意,使用Toyota Car对象找到自己的任何驱动程序对象可能会遇到相同的效果:
LexusDriver driver = new LexusDriver();
driver.drive(ToyotaFactory.newPrius()); // whee!
GreenHornetDriver driver new GreenHornetDriver();
driver.drive(ToyotaFactory.newCorolla()); // wow!
这就是这样的想法:Toyata Cars将自己呈现给司机只是一辆“汽车”,而非“无法控制的汽车”。驱动程序没有耦合到不受控制的加速接口,即,不知道即将发生的事情。一旦他们确实调用加速,并假设这样做不会导致系统崩溃,我们可能会看到Liskov替换原则,即普遍召回原则的罕见推论。
答案 2 :(得分:1)
在我看来,你需要另一种类型的汽车,它需要扩展到一种可以无法控制地加速的汽车,然后让丰田从中继承。
根据你的设计,你说的并不是所有的汽车都能无法控制地加速而打破这是打破你的OO并且是一个不 - 不...抱歉韵。
答案 3 :(得分:1)
我认为Person::drive()
通常会在某个时候调用Car::accelerate()
。我会覆盖Car::accelerate()
中Toyota::accelerate()
的定义,以包含Toyota::accelerateUncontrollably()
。
如果Car::accelerate()
不是虚拟的,并且您无法添加virtual bool Car::isCrazy()
功能,那么就没有好方法可以做到这一点。除了幽默的类比之外,你想要做的就是在没有实际修改类的情况下向Car类添加属性。这样做不会是一个很好的OOD方式。
答案 4 :(得分:0)
我的印象是在这里使用dynamic_cast
绝对没问题。没必要避免它。
答案 5 :(得分:-1)
您可以使用以下模式:
class Car
{
void accelerate();
void stop();
virtual Car* specifyModel(int modelID)
{
return NULL;
}
}
class Person
{
void drive(Car car);
}
#define MODEL_TOYOTA 1
class Toyota : public Car
{
virtual Car* specifyModel(int modelID)
{
if (modelID == MODEL_TOYOTA) return this;
return NULL;
}
void accelerateUncontrollably();
}
class ToyotaDriver : public Person
{
void drive(Car car)
{
Toyota* toyota = static_cast<Toyota*>(car.specifyModel(MODEL_TOYOTA));
if (toyota != NULL)
{
toyota->accelerateUncontrollably();
}
}
}
基本思想是在基类中定义一个虚方法,该方法表示一个带有类型标记并返回指针的“向下转换”函数。如果返回的值不为null,则暗示它可以安全地下载到与该标记匹配的类型。
派生类重写方法,检查其类型标记,并返回有效指针(如果匹配)。