【问题标题】:Using C++ templating for SFML Resource Manager为 SFML 资源管理器使用 C++ 模板
【发布时间】:2014-12-29 23:36:59
【问题描述】:

我正在考虑两种解决方案来为我的 SFML 游戏创建资源管理器。两者都需要模板(我是模板新手),但我更喜欢其中一种解决方案,即使我真的不知道如何使它工作。

我想做这样的事情:

std::map<string, class> resources;

template<class T> T getResource(std::string name){
    return (T) resources.find(name);
}

换句话说,我希望将所有资源存储在一个类中,并且只有一个函数可以获取资源,并且该函数应始终返回资源的类型 - 这样,为了要加载资源,我可以这样做:

Texture texture = resourceManager.getResource("mytexture.png");

但我不知道如何让它工作。

我的第二种方法是模板化一个类,然后实例化多个资源管理器,每个资源管理器一个。

template<class Res> class ResourceManager {
    std::map<string, Res> resources;
    ...
    Res get(std::string name){
        return resources.find(name); //Just to visualize. Of course there would be null checks etc in the real method
    }
}

在我看来,第二个“解决方案”在代码方面看起来更简洁,但第一个更容易使用;而且我可以将方法设为静态,这样我就不必担心解耦了。

我真的不知道我应该把第二种方法的管理器实例放在哪里。可能我会将实例设为静态并将它们放在我的主类中,但这似乎并不正确。

【问题讨论】:

标签: c++ templates resources sfml


【解决方案1】:

虽然不错,但它会变得非常混乱,因为您不能在同一个地图中拥有不同的资源类型。它们没有共同的基类。不过你没有那么多不同的资源,所以我建议你把它们拼出来。

就我个人而言,我讨厌字符串作为标识符,因为编译器找不到错别字,所以我使用的是枚举:

enum ResourceIdentifier
{
    // TEXTURES
    LoadingScreenBackground,
    FireAnimation,
    SmokeAnimation,
    FloorTile,
    // ...

    // FONTS
    MainFont
};

class ResourceManager
{
private:
    std::map<ResourceIdentifier, std::shared_ptr<sf::Texture>> m_Textures;
    std::map<ResourceIdentifier, std::shared_ptr<sf::Font>> m_Fonts;

public:
    std::shared_ptr<sf::Texture> LoadTexture(ResourceIdentifier id, const sf::String& file);
    std::shared_ptr<sf::Font> LoadFont(ResourceIdentifier id, const sf::String& file);

    std::shared_ptr<sf::Texture> GetTexture(ResourceIdentifier id) const;
    std::shared_ptr<sf::Font> GetFont(ResourceIdentifier id) const;
};

【讨论】:

  • 我还将enum 分成不同的类别。
【解决方案2】:

第一种方法行不通,因为您必须知道对象的大小才能将其存储在容器中。这就是为什么没有 class 类型这样的东西的原因。

如果您想使用第一种方法,您可以做的是存储 void* 指针,其大小是已知的,然后让您的函数将此指针返回为正确的指针类型。

std::map<string, void*> resources;

template<class T> T* getResource(std::string name){
    return static_cast<T*>(resources.find(name));
}

这有点脏,而且根本不安全,它可能会损坏,但它可以按您的预期工作。您的第二种方法可能是最好的:-)

【讨论】:

  • static_cast 不会捕捉到将声音作为纹理检索的情况。
  • 是的。但在 C++ 中不使用 C 风格的强制转换仍然是一个好习惯。
  • 我对 C 风格的转换只字未提,它们也不会捕捉到前面提到的无效转换。 dynamic_cast 在这种情况下更为合适和可取。
  • 我很确定在 void 指针上使用 dynamic_cast 是非法操作。
  • 更有理由使用void*。甚至引入一个只有虚拟析构函数的虚拟基类也更符合习惯,更安全,并且允许正确和安全的强制转换。即使是原始帖子中所需的端点示例也使用std::map&lt;string, class&gt; 作为示例,而不是std::map&lt;string, void*&gt;
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-16
  • 2017-02-02
相关资源
最近更新 更多