Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/127.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用C++;SFML资源管理器的模板_C++_Templates_Resources_Sfml - Fatal编程技术网

C++ 使用C++;SFML资源管理器的模板

C++ 使用C++;SFML资源管理器的模板,c++,templates,resources,sfml,C++,Templates,Resources,Sfml,我正在考虑两种解决方案来为我的SFML游戏创建一个资源管理器。两者都需要模板化(我对模板化还不熟悉),但我更喜欢这些解决方案中的一种,即使我真的不知道如何让它工作 我想这样做: std::map<string, class> resources; template<class T> T getResource(std::string name){ return (T) resources.find(name); } 但我不知道如何让它工作 我的第二种方法是模板

我正在考虑两种解决方案来为我的SFML游戏创建一个资源管理器。两者都需要模板化(我对模板化还不熟悉),但我更喜欢这些解决方案中的一种,即使我真的不知道如何让它工作

我想这样做:

std::map<string, class> resources;

template<class T> T getResource(std::string name){
    return (T) resources.find(name);
}
但我不知道如何让它工作

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

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
    }
}
模板类资源管理器{
地图资源;
...
Res-get(标准::字符串名称){
return resources.find(name);//只是为了可视化。当然,在实际方法中会有空检查等
}
}
在我看来,第二个“解决方案”看起来更干净,但第一个更易于使用;我可以让这些方法保持静态,这样我就不用担心解耦了


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

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

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

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;
};
枚举资源标识符
{
//质地
装载筛背景,
火焰动画,
烟雾动画,
地板,
// ...
//字体
主字体
};
班级资源经理
{
私人:
贴图m_纹理;
标准::地图m_字体;
公众:
std::shared_ptr LoadTexture(资源标识符id、常量sf::字符串和文件);
std::shared_ptr LoadFont(资源标识符id、常量sf::字符串和文件);
std::shared_ptr GetTexture(ResourceIdentifier id)const;
std::shared_ptr GetFont(ResourceIdentifier id)const;
};

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

如果要使用第一种方法,您可以做的是存储大小已知的
void*
指针,然后让函数将该指针转换为正确的指针类型

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

template<class T> T* getResource(std::string name){
    return static_cast<T*>(resources.find(name));
}
std::地图资源;
模板T*getResource(标准::字符串名称){
返回静态_cast(resources.find(name));
}

这是一种肮脏的,根本不安全的类型,它可能会打破,但它的工作方式正如你所期望的。你的第二种方法可能是最好的:-)

static\u cast
不会捕捉到将声音作为纹理检索的情况。是的。但是,在C++中不使用C风格的转换仍然是一个好的做法。我对C样式的转换没有任何意见,也不会满足前面提到的无效转换。code>dynamic\u cast在这种情况下更合适、更可取。我很确定对空指针使用
dynamic\u cast
是非法操作。更重要的是,不要使用
void*
。即使引入一个虚拟基类,也不过是一个虚拟析构函数,这更为惯用,更为安全,并允许正确和安全的强制转换。即使是原始文章中所需的端点示例也使用
std::map
作为示例,而不是
std::map
。您可能需要查看或。我会专注于有趣的东西(你的游戏),而不是那些耗时的细节我也会在不同的类别之间拆分
enum
。@Jarod42我在编写代码时没有这样做,但你是对的,这是有意义的。
std::map<string, void*> resources;

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