使用模板在 C++ 中编写 get 组件方法

Fig*_*wig 3 c++ templates components

我正在尝试编写一个 Unity 风格的获取组件方法。这是我到目前为止的代码。它会编译,但会返回它找到的第一个组件,而不是正确的组件。我认为我使用 static_cast 是错误的。有什么更好的方法来做到这一点?请注意,我不想对组件类型进行硬编码,我希望能够编译此引擎并使用从 Component 继承的任何内容以便能够使用此系统。另请注意,每个组件都需要作为其自身返回,而不是组件*,因为这会隐藏子功能。

compStruct.components 是组件 *s 的向量。

template <typename CompType>
inline CompType getComponent()
{
    for(Component * currComp : compStruct.components)
    {
        if (static_cast<CompType>(currComp)!= nullptr)
        {
            return static_cast<CompType>(currComp);
        }
    }
    return nullptr;
}
Run Code Online (Sandbox Code Playgroud)

这是通用组件的示例

#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:

};
Run Code Online (Sandbox Code Playgroud)

以及组件基类:

#pragma once
class GameObject;

class Component
{
public:
    Component(GameObject * h) { host = h; }
    virtual ~Component() {}

    GameObject* getHost() { return host; }

protected:
    GameObject * host = nullptr;
};
Run Code Online (Sandbox Code Playgroud)

Aco*_*gua 6

关于 存在一些根本性的误解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);
Run Code Online (Sandbox Code Playgroud)

d2将是一个指向 d1 的指针(在某些涉及多重继承的情况下,可能会有一个偏移量),但对后者的数据的解释完全不同(除非D1D2是布局兼容的),你可能会陷入地狱!

首先,我个人更喜欢修改后的签名:

template <typename CompType>
inline CompType* getComponent();
//             ^
Run Code Online (Sandbox Code Playgroud)

它允许像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;
Run Code Online (Sandbox Code Playgroud)

编辑:赶上Nshant Singh的评论:

dynamic_cast实际上是相当昂贵的。

另一种方法可以是unordered_map,替换您的向量(如何设置的示例可以在type_index文档中找到;当然,您可以放置​​对象而不是字符串......)。那么你的查找可能如下所示:

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!
Run Code Online (Sandbox Code Playgroud)