【问题标题】:How to avoid using dynamic_cast, when implementing external actions?在执行外部操作时如何避免使用 dynamic_cast?
【发布时间】:2014-09-12 06:14:22
【问题描述】:

dynamic_cast 是纯粹的邪恶。每个人都知道。只有菜鸟使用 dynamic_cast。 :)

这就是我读到的关于 dynamic_cast 的内容。 stackoverflow 上的许多主题都说“在这种情况下使用虚函数”。

我有一些反映对象功能的接口。比方说:

class IRotatable
{
  virtual void set_absolute_angle(float radians) =0;
  virtual void rotate_by(float radians) =0;
};

class IMovable
{
  virtual void set_position(Position) =0;
};

以及一组可以实现它们的类的基础:

class Object
{
  virtual ~Object() {}
};

在 GUI 层中,我想根据用户选择的对象实现的功能启用/禁用或显示/隐藏按钮:

Object *selected_object;

我会这样做(简化):

button_that_rotates.enabled = (dynamic_cast<IRotatable*>(selected_object) != nullptr);

(...)

void execute_rotation(float angle)
{
  if(auto rotatable = dynamic_cast<IRotatable*>(selected_object))
  {
    rotatable->rotate_by(angle);
  }
}

但正如其他(更有经验的人)所说,这是糟糕设计的明显证据。

在这种情况下,什么是好的设计?

不,我不希望我的Object 中有一堆虚函数。我希望能够在不接触Object 的情况下添加实现它的新接口和新类(以及新按钮)。

Object 中的 get_buttons 之类的虚函数对我来说似乎也不好。我的Object 对 GUI、按钮之类的东西一无所知。

get_type 这样返回一些枚举的函数也可以解决问题,但我不明白为什么 RTTI 的自我实现替代品应该比原生替代品更好(好吧,它会更快,但它没有在这种情况下没关系)。

【问题讨论】:

  • 这是一个很好的问题programmers.stackexchange.com
  • 如果不知道selected_object 是什么,就无法回答这个问题。从表面上看,您根本不需要演员表。
  • 我在selected_object上添加了一些基本信息
  • 避免动态转换的一般方法是首先不要丢弃类型信息。您可能会发现访问者模式很有用。对于非常紧密耦合的类,它可以让您完全避免强制转换,否则它可以让您集中强制转换。但首先要认真考虑如何更改您的设计,以避免丢弃所需的信息。例如,考虑两个或多个更受限制且直接有用的集合,而不是所有东西的大集合。
  • “dynamic_cast 是纯粹的邪恶”。好吧,它仍然是检查类是否在运行时实现特定接口的唯一方法。对接口的动态转换并不邪恶...

标签: c++ dynamic-cast


【解决方案1】:

您已经一针见血:您正试图从“不透明”的 Object* 类型中获取类型信息。使用 dynamic_cast 只是一个技巧。可以说你的问题实际上是 C++ 没有你想要的:好的类型信息。但这里有一些想法。

首先,如果您要做很​​多此类事情,您可能会发现您实际上正在远离典型的继承,并且您的程序可能更适合基于组件的设计模式,这在视频游戏。在那里,您经常在根部有一个有点不透明的游戏对象,并且想知道它有哪些“组件”。 Unity 会做这种事情,并且它们有很好的基于附加到游戏对象的组件的编辑器窗口;但 C# 也有很好的类型信息。

其次,其他部分可能知道对象的具体类型,可以帮助构建您的视觉显示,从而使 Object* 不再是瓶颈。

第三,如果您确实选择了您正在谈论的选项,我认为您会发现使用某种类型的 id 与使用 dynamic_cast 相比更有帮助,因为您可以构建表格以查看最多类型说,视觉建设者。

另外,您想知道为什么自卷类型信息与 RTTI 相比?如果您非常关心性能,RTTI 适用于所有类型,这意味着一切都会受到影响;自滚动选项允许选择加入(以复杂性为代价)。此外,如果您正在编写通过源等方式引入的库,则无需将其推送给其他人。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-10
    • 1970-01-01
    • 2016-03-19
    • 2010-10-02
    • 1970-01-01
    • 2016-08-24
    相关资源
    最近更新 更多