绕过 RTTI 的不同方法的优点

Advantages of different methods for bypassing RTTI

假设我想要一个可以使用 Base-Class/Interface Animal 管理不同动物的程序。动物可以有特定的行为 (Fly/Climb/ThrowPoo)。目标是迭代 list<Animal*> 并使用它们的特定行为对它们执行一些操作。

首先想到的是使用 dynamic_caststatic_cast + typeid 来转换 Animal*。但是这种方法很难维护,如果我有更多的对象要迭代,它会变得很慢。

经过一番研究,我发现了以下避免 RTTI 并改用虚函数调用的方法:

  1. Animal class.
  2. 中将动物可能拥有的每个方法声明为虚拟方法
  3. 使用动态调度模式,例如访问者模式。

在我看来,这两种方法都有其自身的缺陷。第一个污染动物 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,只是乱用。