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

问题描述 投票:3回答:2

我正在尝试编写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;
};
c++ templates components
2个回答
4
投票

static_cast绝对不是你想要的:它是静态的(编译时),所以它无法确定任何运行时信息。

你想要的是dynamic_cast。请注意,这有几个要求,所有这些要求都由您的代码完成:

  • 这些类必须是多态的。这是因为Component有一个虚拟的析构函数。
  • 必须在演员阵容中定义(不仅仅是声明)类。这也包括在内,因为getComponent是一个模板,而模型中的类型取决于它的模板参数(事实上它是一个)。因此,只有在实例化模板的地方(即调用getComponent的地方)才能看到定义。由于您可能正在进行铸造以访问混凝土构件的构件,因此必须使其定义可见,因此一切都很好。

3
投票

关于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的指针(在某些情况下涉及多重继承,可能有一个偏移),但是完全不同地解释后者的数据(除非D1D2是布局兼容的),你最终可能会陷入地狱!

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

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!
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.