面向对象设计播放器和AI控制单元.dynamic_cast
OOP Design Player and AI Controlled Unit. dynamic_cast?
假设我有一个Actor类型,它可以是我的游戏关卡上的任何可放置对象。我还有Unit,它是Actor的子类。单位可以是玩家,也可以是AI控制的英雄。
Unit也有两个子类:Player(玩家)和Hero (AI控制的单位)。在单位类中,会有移动信息,旋转,以及其他玩家和英雄都需要的一般设置。在子类中,AI将拥有与玩家不同且更多的功能。
现在我面临着以下问题:
一个函数只接受Actor作为参数(例如OnOverlap(Actor a*)
)但是OnOverlap()
只有当它是一个单位职业(英雄或玩家)时才应该做一些事情。因此,我需要一些像instanceof()
从Java在c++。
一个解决方案是要么使用dynamic_cast
,但我不确定这是否是一个好主意的性能。或者使用virtual,但是当Hero拥有比Player更多的功能时,这将不起作用。
我想说dynamic_cast
是代码气味。从本质上讲,这并不一定是坏事,但这表明你的设计可能出了问题。
OOP中的一个重要概念是多态性:对象的行为取决于它们的类型而不同,这种行为被封装在中,隐藏在接口后面。如果你显式地检查一个对象的类型来改变你想要应用到它的逻辑,那么你就违反了多态性。
现在虚拟方法也不是那么好,它们确实会产生运行时成本,并且有时会给表带来太多的复杂性。c++使virtual
方法成为例外,而不是默认的,我相信正是出于这些原因。
您应该知道的一件事是,虚拟方法只是一种多态性,称为动态多态性。还有另一种方法可以根据对运行时影响较小的类型获得不同的行为:静态多态性,即模板元编程。但这在复杂性方面并没有真正的帮助。
在这种情况下,你真正应该做的是分开对待不同的东西。你可能想在Units
上有这个OnOverlap()
方法是有原因的:假设你只在Units
上做碰撞检查,而不是所有的Actors
。然后维护一个单独的Units
列表,并使OnOverlap()
方法在Unit
类上是非虚拟的。这种思维方式往往是关键。
这种技术称为运行时类型信息(RTTI),检查dynamic_cast的输出是否为NULL是一种有效的实现。
另一种方法是#include <typeinfo>
,并使用typeid(*a).name()
来获取a的类型的字符串名称。
需要使用dynamic_cast
通常(尽管并不总是)表明您存在设计缺陷。在这种情况下,我认为你需要。
如果不进一步评论您所描述的体系结构的总体设计,我想说使用虚拟方法是正确的方法。让OnOverlap
接受它的actor并在actor上调用OnOverlapped
方法,也许给它一个指向执行初始OnOverlap
方法的指针(从你的问题中不清楚那是什么(*))。
void X::OnOverlap (Actor * actor) {
actor->OnOverlapped(this);
}
OnOverlapped
本身是虚的。这允许您在actor单元的情况下"做正确的事情",但在其他地方不做任何事情或其他一些默认行为。您是正确的,在这种情况下,这意味着您只能使用Actor
的公共API。您必须将任何需要Player
的附加方法的内容移到OnOverlapped
的Player
实现中。如果您真的认为由于某些原因不能这样做,那么您可能应该考虑在更高级别上的替代设计(并且可能需要编辑您的问题以提供有关您的体系结构的更多细节)。
(*)我最初读到你的问题让我认为OnOverlap
已经不是Actor
的方法了;那是不相关事件的一部分。如果是Actor
的部分,您可能会对一种称为双重分派的模式感兴趣,这种模式可用于这种"冲突处理"类型的问题,并且也是一种使用动态分派(虚拟)的技术。
这些函数是由我的引擎预定义的,其中参数必须而是父函数"Actor"。所以如果任何Actor与网格,函数被调用。在这种情况下,我看不到其他的解决方案,而不是获取Actor对象的实例来知道它是否存在玩别的东西
Actor基类中的简单虚函数可以是noop。在单位类中覆盖它,如果需要的话,可以在英雄和玩家类中更专门化它。非单元Actor将调用空方法。比RTTI和instanceof习惯用法干净。
可以有一个默认的基本实现,期望被专门化的后代覆盖。这就是抽象基类的意义所在,除非在这种情况下,您提供的是一个什么都不做的默认实现。这个想法是,你正在调度"DoCollision"消息(c++中的虚函数)。您不关心哪些类处理它或如何处理它。只要对象有DoCollision编译时"接口",并且你正确地分派了它。
- 如何理解C++标准N3337中的expr.const.cast子句8
- C++Cast运算符过载
- 在成员dynamic_bitset上使用 boost::from_block_range 时出错,但在本地dynamic
- C++类中的二维"dynamic"数组?
- 错误:"cast"未命名类型void setCastDescription(std::string
- 通过使用 const-cast 的非常量引用来延长临时的寿命
- "(void) cast"与功能有什么区别 "__attributes__"来沉默未使用的参数警告?
- protobuf in C++ with dynamic binding for google::protobuf::M
- 警告的原因是什么:"when type is in parentheses, array cannot have dynamic size"?
- C++:"Expected '(' for function-style cast or type construction"错误
- 为什么选择 g++ 给予者:"error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]"
- CUDA 错误:"dynamic initialization is not supported for __device__, __constant__ and __shared__ variabl
- Gtk+ g_signal_connect() 和 C++ lambda 会导致"invalid cast"错误
- 如何修复'The procedure entry point SDL_RWclose could not be located in the dynamic link library'
- Shared_ptr cast vs static_cast speed
- 在 iOS 上使用 Aruco 构建 OpenCV 时"Functional-style cast from id to double is not allowed"
- "The ordinal 344 could not be located in the dynamic link library"
- 覆盖 CAST 运算符(我认为它被称为向下转换)
- Dynamic Cast C++ Fail
- dynamic-cast-c++dynamic_cast错误处理