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