假设我想要一个可以使用基类/接口(interface)管理不同动物的程序 Animal
.动物可以有特定的行为(飞行/攀爬/扔便便)。目标是遍历 list<Animal*>
并使用他们的特定行为对他们执行一些操作。
首先想到的就是类型转换 Animal*
使用 dynamic_cast
或 static_cast
+ typeid
.但是这种方法很难维护,如果我有更多的对象要迭代,它会变得非常慢。
经过一些研究,我发现了以下避免 RTTI 并改用虚函数调用的方法:
- 在
Animal
中将动物可能拥有的所有方法声明为虚拟方法类。 - 使用动态调度模式,例如访问者模式。
在我看来,这两种方法都有其自身的缺陷。第一个污染了动物类及其派生类,其中包含大量丰富的代码/实用程序,您将需要一些方法,例如 bool canFly()
如果你想避免特定的函数调用(例如,如果函数保证调用时的某些行为)。我非常喜欢第二种方法,但它远没有前一种方法那么容易阅读和理解。
您能否详细说明转换 (RTTI)、虚函数和动态调度模式的优点/缺点以及何时正确使用它们?另外,如果我遗漏了任何方法或策略,请将它们包括在比较中。
最佳答案
我认为当您考虑 dynamic_cast
时,您正在设想 makeYourSound(Animal* a)
功能由两百个组成 if...else if
block ,每个 block 测试和处理特定类型的动物。是的,那很慢而且无法维护。不要这样做。
什么 dynamic_cast
确实有利于可选接口(interface)。有些动物可以做的特定事情,而其他动物则不能。 if(Eagle* e = dynamic_cast<Eagle*>(a))
是一种代码味道,而且很糟糕。 if(IFly* f = dynamic_cast<IFly*>(a))
闻起来少得多。它避免了代码重复,它避免了用无意义的方法污染基类和围绕如何处理非飞行动物跳踢踏舞,并且它在你的代码中更准确地描述了你正在尝试做什么。
基于虚函数的多态性的优点是对象完全掌控,这对 OO 纯粹主义者有极大的吸引力。但在某些情况下,作为一名实际的程序员,您并不希望对象处于控制之下,只是告诉您的代码更多关于自身的信息,以便它能够得到妥善处理。更细致的指南,如 OCP,适用范围更广,并且不排除 dynamic_cast
, 只是乱用而已。
关于c++ - 绕过 RTTI 的不同方法的优点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31493677/