在实施外部操作时如何避免使用dynamic_cast?

时间:2014-09-12 06:14:22

标签: c++ dynamic-cast

dynamic_cast是纯粹的邪恶。大家都知道。只有noobs使用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的情况下添加新界面和实现它的新类(以及新按钮)。

get_buttonsObject之类的虚拟函数对我来说似乎并不好。我的Object完全不了解GUI,按钮等等。

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

1 个答案:

答案 0 :(得分:1)

你已经敲了敲头:你正试图从“不透明的”对象*类型中获取类型信息。使用dynamic_cast只是一个黑客到达那里。可以说你的问题实际上是C ++没有你想要的东西:良好的类型信息。但是这里有一些想法。

首先,如果你要做很多这类事情,你可能会发现你实际上已经脱离了典型的继承,你的程序可能更适合基于组件的设计模式,这在视频游戏。在那里,你经常在根处有一个不透明的GameObject,想知道它有什么“组件”。 Unity做了这样的事情,他们有很好的编辑器窗口,基于附加到GameObject的组件;但是C#也有很好的类型信息。

其次,可能的其他部分可能知道对象的具体类型,并且可以帮助构建您的可视化显示,从而导致Object *不再成为瓶颈。

第三,如果你选择了类似你正在讨论的选项,我认为你会发现某种类型的id与使用dynamic_cast更有帮助,因为你可以构建表格来查看可以说,视觉建设者。

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