如何将字符串(ID)映射到新子类对象的创建C++
How to map a string (ID) to the creation of a new subclass object c++
我研究了很多,但我似乎找不到任何实际可行的方法,或者如果可能的话。我需要的是一个对象工厂或注册表,我相信,我不知道如何,也没有线程真正有帮助。他们通常使用我根本不熟悉的想法,所以很难理解。
在我的示例中,我有一个名为 Art
的父 class 和一堆 Art
类型的子 class(例如 FireBolt
).我希望用户能够自由地将 FireBolt
对象添加到他们的 Arts
列表中,而不必在任何地方包含 FireBolt
对象。因此,仅通过 Art
对象,我需要一种方法来创建 Art
和 return 的新子对象 class。这个想法是,它将像一个 console/god 模式类型的交易,用户可以在任何给定时间添加他们喜欢的任何东西。我知道像 Skyrim 这样的游戏有这个 ID 系统,但我不知道该怎么做。
我尝试简单地将一个字符串映射到一个 Art* 对象 (std::map<std::string, Art*> artMap
),并使用一个名为 regArt(std::string ID, Art* art)
的函数,但每当我尝试使用它时它 return这是错误 "error: expected constructor, destructor, or type conversion before '(' token"。此外,我相信这将意味着每个人都共享 Art
的单一版本,并且在游戏规范中,Art
可以在游戏中期更改。
请注意,我已链接到其他尝试解决相同问题的线程,但我无法让它们在我的示例中工作。很多评论简单地说 'This does not work'.
一些可能无用的代码;
Art.h;
class Art {
std::string name;
int EPCost;
int castTime;
int AoESize;
std::string ID;
public:
Art(std::string n, int cp, int ct, int as):name(n), EPCost(cp), castTime(ct), AoESize(as) {}
virtual ~Art() {}
int getAoESize() {return AoESize;}
std::string getName() {return name;}
int getEPCost() {return EPCost;}
virtual int getBaseDamage() = 0;
};
FireBolt.h;
class FireBolt:public Art {
static const std::string name;
static const int EPCost;
static const int castTime;
static const int AoESize;
public:
FireBolt():Art(name, EPCost, castTime, AoESize) {}
~FireBolt() {}
int getBaseDamage();
};
所以在玩了很多很多小时之后,我有一些东西是可以的。我不完全认为我想做的事是可能的,或者如果是的话我根本不知道怎么做。这就是我解决的问题。
我用以下头文件和源文件制作了一个名为 ArtFactory
的新 class(尚未决定是否将其扩展到游戏中的所有内容,即设备、攻击等);
ArtFactory.h;
#include "Arts.h"
#include "FireBolt.h"
#include <functional>
class ArtFactory {
static std::map<std::string, std::function<Art*()>> artMap;
public:
ArtFactory();
static void loadArts();
static Art* getNewArt(std::string ID) {return artMap.find(ID)->second();}
static void regArt(std::string ID, std::function<Art*()> f) {artMap[ID] = f;}
};
这将字符串 (ID) 映射到静态映射中的 lambda 函数。如果您输入正确的 ID,lambda 函数将简单地 return 一个我们想要的 Art
的新版本,从而允许它生成许多相同的 Art
,这意味着我不是每个必须在任何地方初始化一个 ArtFactory
。我需要在这个文件中#include 我制作的每一个艺术作品,这很不幸,但我认为这是必要的。如果没有,我会喜欢一种不需要的方法。
源文件,cpp文件;
#include "ArtFactory.h"
std::map<std::string, std::function<Art*()>> ArtFactory::artMap;
ArtFactory::ArtFactory() {
return;
}
void ArtFactory::loadArts() {
artMap["001A"] = []() -> Art* {return new FireBolt();};
}
然后要扩展它,只需复制 loadArts 中的行并将 ID(在本例中为“001A”)替换为新 ID 和新的 class(在本例中为 FireBolt()
)使用新 class。
我不喜欢的是,如果我 #include "ArtFactory.h"
在任何地方,我也会包括所有其他艺术作品。这种方法并没有消除link对其他艺术的需要,事实上恰恰相反。在这个游戏中,某些 characters/enemies 以某些 arts/attacks 开头,而某些项目带有这些 arts/attacks,所以最好包含我需要的特定 art/attack 而不是使用这个工厂。
实施 console/god 模式很有用,因为我现在可以轻松列出所有可用的艺术及其 ID,以及 return 新艺术。我真诚地希望这在某些时候对某人有所帮助。被这个问题困了好久都没找到好帖
我研究了很多,但我似乎找不到任何实际可行的方法,或者如果可能的话。我需要的是一个对象工厂或注册表,我相信,我不知道如何,也没有线程真正有帮助。他们通常使用我根本不熟悉的想法,所以很难理解。
在我的示例中,我有一个名为 Art
的父 class 和一堆 Art
类型的子 class(例如 FireBolt
).我希望用户能够自由地将 FireBolt
对象添加到他们的 Arts
列表中,而不必在任何地方包含 FireBolt
对象。因此,仅通过 Art
对象,我需要一种方法来创建 Art
和 return 的新子对象 class。这个想法是,它将像一个 console/god 模式类型的交易,用户可以在任何给定时间添加他们喜欢的任何东西。我知道像 Skyrim 这样的游戏有这个 ID 系统,但我不知道该怎么做。
我尝试简单地将一个字符串映射到一个 Art* 对象 (std::map<std::string, Art*> artMap
),并使用一个名为 regArt(std::string ID, Art* art)
的函数,但每当我尝试使用它时它 return这是错误 "error: expected constructor, destructor, or type conversion before '(' token"。此外,我相信这将意味着每个人都共享 Art
的单一版本,并且在游戏规范中,Art
可以在游戏中期更改。
请注意,我已链接到其他尝试解决相同问题的线程,但我无法让它们在我的示例中工作。很多评论简单地说 'This does not work'.
一些可能无用的代码;
Art.h;
class Art {
std::string name;
int EPCost;
int castTime;
int AoESize;
std::string ID;
public:
Art(std::string n, int cp, int ct, int as):name(n), EPCost(cp), castTime(ct), AoESize(as) {}
virtual ~Art() {}
int getAoESize() {return AoESize;}
std::string getName() {return name;}
int getEPCost() {return EPCost;}
virtual int getBaseDamage() = 0;
};
FireBolt.h;
class FireBolt:public Art {
static const std::string name;
static const int EPCost;
static const int castTime;
static const int AoESize;
public:
FireBolt():Art(name, EPCost, castTime, AoESize) {}
~FireBolt() {}
int getBaseDamage();
};
所以在玩了很多很多小时之后,我有一些东西是可以的。我不完全认为我想做的事是可能的,或者如果是的话我根本不知道怎么做。这就是我解决的问题。
我用以下头文件和源文件制作了一个名为 ArtFactory
的新 class(尚未决定是否将其扩展到游戏中的所有内容,即设备、攻击等);
ArtFactory.h;
#include "Arts.h"
#include "FireBolt.h"
#include <functional>
class ArtFactory {
static std::map<std::string, std::function<Art*()>> artMap;
public:
ArtFactory();
static void loadArts();
static Art* getNewArt(std::string ID) {return artMap.find(ID)->second();}
static void regArt(std::string ID, std::function<Art*()> f) {artMap[ID] = f;}
};
这将字符串 (ID) 映射到静态映射中的 lambda 函数。如果您输入正确的 ID,lambda 函数将简单地 return 一个我们想要的 Art
的新版本,从而允许它生成许多相同的 Art
,这意味着我不是每个必须在任何地方初始化一个 ArtFactory
。我需要在这个文件中#include 我制作的每一个艺术作品,这很不幸,但我认为这是必要的。如果没有,我会喜欢一种不需要的方法。
源文件,cpp文件;
#include "ArtFactory.h"
std::map<std::string, std::function<Art*()>> ArtFactory::artMap;
ArtFactory::ArtFactory() {
return;
}
void ArtFactory::loadArts() {
artMap["001A"] = []() -> Art* {return new FireBolt();};
}
然后要扩展它,只需复制 loadArts 中的行并将 ID(在本例中为“001A”)替换为新 ID 和新的 class(在本例中为 FireBolt()
)使用新 class。
我不喜欢的是,如果我 #include "ArtFactory.h"
在任何地方,我也会包括所有其他艺术作品。这种方法并没有消除link对其他艺术的需要,事实上恰恰相反。在这个游戏中,某些 characters/enemies 以某些 arts/attacks 开头,而某些项目带有这些 arts/attacks,所以最好包含我需要的特定 art/attack 而不是使用这个工厂。
实施 console/god 模式很有用,因为我现在可以轻松列出所有可用的艺术及其 ID,以及 return 新艺术。我真诚地希望这在某些时候对某人有所帮助。被这个问题困了好久都没找到好帖