C++ 使用C++;SFML资源管理器的模板
我正在考虑两种解决方案来为我的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); } 但我不知道如何让它工作 我的第二种方法是模板
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));
}