我正在尝试编写Unity样式的get组件方法。到目前为止这是我的代码。它编译但会返回它找到的第一个组件而不是正确的组件。我想我正在使用static_cast错误。有什么更好的方法呢?注意我不想硬编码组件类型,我希望能够编译此引擎并使用从Component继承的任何东西才能使用此系统。另请注意,每个组件都需要作为自身返回,而不是组件*,因为这会隐藏子功能。
compStruct.components是组件*的向量。
template <typename CompType>
inline CompType getComponent()
{
for(Component * currComp : compStruct.components)
{
if (static_cast<CompType>(currComp)!= nullptr)
{
return static_cast<CompType>(currComp);
}
}
return nullptr;
}
这是一个通用组件的示例
#pragma once
#include "Component.h"
#include "Animation2D.h"
class AnimationComponent : public Component
{
public:
AnimationComponent(GameObject*x) :Component(x) {}
~AnimationComponent() {}
void stepAnimation(double delta);
//add overload for 3d animations
int addAnimation(Animation2D);
void setAnimation(int);
private:
};
和组件基类:
#pragma once
class GameObject;
class Component
{
public:
Component(GameObject * h) { host = h; }
virtual ~Component() {}
GameObject* getHost() { return host; }
protected:
GameObject * host = nullptr;
};
static_cast
绝对不是你想要的:它是静态的(编译时),所以它无法确定任何运行时信息。
你想要的是dynamic_cast
。请注意,这有几个要求,所有这些要求都由您的代码完成:
Component
有一个虚拟的析构函数。getComponent
是一个模板,而模型中的类型取决于它的模板参数(事实上它是一个)。因此,只有在实例化模板的地方(即调用getComponent
的地方)才能看到定义。由于您可能正在进行铸造以访问混凝土构件的构件,因此必须使其定义可见,因此一切都很好。关于static_cast
有一些基本的误解:它只会做演员,你有责任确保指针实际上指向目标类型的对象。 static_cast
只会返回一个空指针,如果源指针本身已经存在,但永远不会出现类型不匹配!
class B { /*...*/ };
class D1 : public B { };
class D2 : public B { };
D1 d1;
B* b = &d1;
D2* d2 = static_cast<D2*>(b);
d2
将是一个指向d1的指针(在某些情况下涉及多重继承,可能有一个偏移),但是完全不同地解释后者的数据(除非D1
和D2
是布局兼容的),你最终可能会陷入地狱!
现在首先,我个人更喜欢修改后的签名:
template <typename CompType>
inline CompType* getComponent();
// ^
它允许调用你的函数,如getComponent<SomeType>()
而不是getComponent<SomeType*>()
,另外它允许在函数体内使用指针,这更清晰,请参阅下面我的适当调整的代码。
然后你真正需要的是一个dynamic_cast
(根据我个人的喜好调整你的代码......):
CompType* result = nullptr; // pointer: see above!
for(Component * currComp : compStruct.components)
{
result = dynamic_cast<CompType*>(currComp);
if(result)
break;
}
return result;
编辑:赶上Nshant Singh的评论:
dynamic_cast
实际上相当昂贵。
另一种选择可能是unordered_map
,替换你的矢量(例如如何设置可以在type_index
documentation找到;当然,你放置你的对象而不是字符串...)。然后您的查找可能如下所示:
auto i = map.find(std::type_index(typeid(CompType));
return i == map.end() ? nullptr : static_cast<CompType*>(i->second);
// now, you CAN use static cast, as the map lookup provided you the
// necessary guarantee that the type of the pointee is correct!