C++ 在执行外部操作时,如何避免使用动态_cast?
动态施法是纯粹的邪恶。大家都知道。只有noob使用动态_cast.:) 这就是我读到的关于dynamic_cast的内容。关于stackoverflow的许多主题都说“在这种情况下使用虚拟函数” 我有一些反映对象功能的接口。比如说:C++ 在执行外部操作时,如何避免使用动态_cast?,c++,dynamic-cast,C++,Dynamic Cast,动态施法是纯粹的邪恶。大家都知道。只有noob使用动态_cast.:) 这就是我读到的关于dynamic_cast的内容。关于stackoverflow的许多主题都说“在这种情况下使用虚拟函数” 我有一些反映对象功能的接口。比如说: class IRotatable { virtual void set_absolute_angle(float radians) =0; virtual void rotate_by(float radians) =0; }; class IMovabl
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;
我会这样做(简化):
旋转的按钮。\u.enabled=(动态\u投射(选定的\u对象)!=nullptr);
(...)
无效执行旋转(浮动角度)
{
if(自动旋转=动态投影(选定对象))
{
可旋转->旋转(角度);
}
}
但正如其他(更有经验的)人所说,这显然是糟糕设计的证据
在这种情况下,什么是好的设计
不,我不想在我的对象中有一堆虚拟函数。我希望能够添加实现它的新接口和新类(以及新按钮),而无需触摸对象
另外,虚拟功能,如通过Object
中的get\u按钮
,对我来说似乎不太合适。我的对象
完全不知道GUI、按钮之类的东西
像get_type
这样返回一些枚举的函数也可以解决一个问题,但我不明白为什么RTTI的自实现替代应该比本地替代更好(好的,它会更快,但在这种情况下并不重要)。您已经一针见血了:您试图从“不透明”数据库获取类型信息对象*类型。使用dynamic_cast只是一种达到目的的技巧。可以说,你的问题实际上是C++没有你想要的:好的类型信息。但这里有一些想法
首先,如果你打算做很多类似的事情,你可能会发现你实际上正在从典型的继承转移,你的程序可能更适合基于组件的设计模式,这在视频游戏中更常见。在那里,你经常在根目录下有一个不透明的游戏对象,你想知道它有什么“组件”。Unity就是这样做的,他们有很好的编辑器窗口,基于附加到游戏对象的组件;但C#也有很好的类型信息
其次,系统的其他部分可能知道对象的具体类型,并可以帮助构建可视化显示,从而使对象*不再成为瓶颈
第三,如果你真的使用了你所说的选项,我想你会发现拥有某种类型的类型id比使用dynamic_cast更有帮助,因为你可以构建表格来查找类型,比如说可视化构建器
此外,您还想知道为什么自卷类型info与RTTI相比?如果您非常关心性能,RTTI适用于所有类型,这意味着一切都可能受到冲击;自滚动选项允许选择加入(以复杂性为代价)。此外,如果您正在编写通过源代码等方式拉入的库,则无需将此推给其他人。这将是一个很好的问题。如果不知道所选对象是什么,则无法回答此问题。从表面上看,你根本不需要强制转换。我在selected\u 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);
}
}