如何将字符串(ID)映射到新的子类对象C 的创建



我已经研究了很多东西,但是我似乎找不到任何可以实际起作用的东西,或者如果可能的话。我需要的是对象工厂或我相信的注册表,我不知道如何和没有线程真正有所帮助。他们通常使用我根本不熟悉的想法,因此很难遵循。

在我的示例中,我有一个名为Art的父班和Art类型的一堆子类(例如FireBolt)。我希望用户能够在Arts列表中自由地添加FireBolt对象,而不必在任何地方都包含FireBolt对象。因此,仅通过Art对象,我需要一种创建Art的新子类并返回的方法。这个想法是,它就像一个游戏机/上帝模式类型的交易,用户将能够在任何给定时间添加他们喜欢的任何东西。我知道像Skyrim这样的游戏具有此ID系统,但是我不确定该怎么做。

我尝试简单地将字符串映射到Art*对象(std::map<std::string, Art*> artMap),并使用一个称为regArt(std::string ID, Art* art)的函数,但是每当我尝试使用此函数时,它都会返回错误"错误":"错误:预期构造函数,destructor"或" type转换"'("令牌"。此外,我相信这将意味着每个人都共享Art的单个版本,在游戏规范中,Art可以更改中游戏。

请注意,我已经链接到其他试图解决相同问题的线程,但我无法让它们在示例中工作。答案的很多评论只是说"这不起作用"。

一些可能无用的代码;

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的新类(不确定是否仅将其扩展到游戏中的所有内容,即设备,攻击,ECT),并使用以下标头和源文件;

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函数。lambda函数将简单地返回我们想要的Art的新版本,如果您放入正确的ID,则允许它使许多相同的Art都可以返回,这意味着我不必在任何地方初始化ArtFactory。我需要在此文件中#CUNCLUDE,这是不幸的,但我认为这是有必要的。如果没有,我会喜欢不必这样做的方法。

源文件,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替换ID(在这种情况下为" 001a"),并将新类(在这种情况下为FireBolt())用新类替换。

我不喜欢的是,如果我在任何地方#include "ArtFactory.h",我也包括其他所有艺术品。这种方法并没有消除与其他艺术联系的需求,实际上相反。在此游戏中,某些角色/敌人从某些艺术/攻击开始,某些物品带有这些艺术/攻击,因此最好包括我需要的特定艺术/攻击而不是使用该工厂。

它对实施控制台/上帝模式将很有用,因为我现在可以轻松地列出所有可用的艺术和ID,并返回新艺术。我衷心希望这对某人有所帮助。我很长一段时间以来一直困扰着这个问题,但找不到任何好线程。

最新更新