【问题标题】:C++ Instantiate class from string, read from a file [duplicate]C ++从字符串实例化类,从文件中读取[重复]
【发布时间】:2015-12-21 04:38:20
【问题描述】:

编辑:问题是我试图在我的 cpp 文件的全局范围内调用一个静态函数,但由于某种原因它不起作用:

//Player.cpp
RTTI::instance()->registerClass(...) // ERROR
Player::Player() {}
Player::~Player() {}

为了解决这个问题,我将代码更改如下:

template <class T>
struct RTTIRegister {   
    RTTIRegister<T>(const std::string& name) { 
        RTTI::instance()->registerClass(name, &T::createInstance); 
    } 
};

#define PROTOTYPE_CREATE(CLASS, BASE) \     
    static BASE* createInstance() { return new CLASS(); }

#define PROTOTYPE_REGISTER(NAME, CLASS) \   
    RTTIRegister<CLASS> __rtti__(NAME);

我正在尝试编写一个类/宏,这将使我能够创建类的实例,我将其名称存储在字符串中,从文件中读取。我有很多 GameObject 类的派生类。当我使用下面的代码时,它在 Visual Studio C++ 2012 Express 中出现错误:

Error   2   IntelliSense: a trailing return type requires the 'auto' type specifier Player.cpp
Error   1   error C2061: syntax error : identifier 'registerClass'  player.cpp

为什么我会收到此错误,我该如何解决?

代码:

// JSON 
{
    "GameObjects" : [
        {
            "Class" : "Player",
            "Health" : 15
        }
    ]
}

现在,当我的程序读取文件时,它应该创建一个 Player 类的实例。我目前拥有的是以下内容:

class RTTI
{
    typedef GameObject* (*createFunc)(void);

    public:
        static RTTI* instance();
        void registerClass(const std::string& className, createFunc instantiate);
        GameObject* createGameObject(const std::string& className);
    private:
        static RTTI* s_instance;
        std::map<std::string, createFunc> s_registeredClases;
};

#define PROTOTYPE_CREATE(CLASS) \
    static CLASS* createInstance() { return new CLASS(); }

#define PROTOTYPE_REGISTER(NAME, CLASS) \
    RTTI::instance()->registerClass(NAME, &CLASS::createInstance);

现在我的播放器类定义为:

//Player.h
class Player : public GameObject
{
    PROTOTYPE_CREATE(Player)
}

//Player.cpp
PROTOTYPE_REGISTER("Player", Player) /* **THIS IS WHERE IT GIVES ME AN ERROR */
Player::Player() {}
Player::~Player() {}

注册一个类后,我应该可以通过说 RTTI::createGameObject("Player"); 来创建实例

【问题讨论】:

  • 在互联网上搜索“工厂设计模式 c++”。
  • 你可能想参加一些键盘/打字课程,这样你就可以摆脱邪恶的宏。
  • 我不喜欢 clone() 方法策略,因为我不会在读取文件之前创建任何实例。我也不知道会有多少课。

标签: c++


【解决方案1】:

您的障碍之一是创建函数的返回类型。大多数 factory 模式都返回一个指向基类对象的指针,换句话说就是一个返回类型。

工厂可以像一堆 switch 语句一样简单,也可以使用 lookup 表。

查找表将由一列中的键或字符串和第二列中指向创建函数的指针组成。在键列中搜索匹配的字符串,然后使用函数指针(在同一行中)创建该实例。同样的障碍:创建函数必须在表中具有相同的签名(相同的返回类型)。

【讨论】:

  • 查找表正是我想要的。
【解决方案2】:

您尚未在 RTTI 类中定义静态 instance() 成员函数。但是您正在宏中访问它:

#define PROTOTYPE_REGISTER(NAME, CLASS) \
RTTI::instance()->registerClass(NAME, &CLASS::createInstance);

PROTOTYPE_REGISTER 也需要 2 个参数。

定义 PROTOTYPE_CREATE(BASE, CLASS) \

static BASE* createInstance() { return new CLASS(); }

在播放器类中替换您对 PROTOTYPE_CREATE 的调用 和 PROTOTYPE_CREATE(GameObject, Player)

【讨论】:

  • 对此我很抱歉,我已经缩短了代码,忘记添加了。现在上面的代码是正确的,但我仍然得到错误。
  • 如果将 PROTOTYPE_CREATE 更改为 #define PROTOTYPE_CREATE(BASE, CLASS) \ static BASE* createInstance() { return new CLASS(); } 它应该可以工作
【解决方案3】:
try this: Very small difference from your code:

struct GameObject {

};
typedef GameObject* (*createFunc)(void);
class RTTI
{

public:
    static RTTI* instance();
    void registerClass(const std::string& className, createFunc instantiate);
    GameObject* createGameObject(const std::string& className);
private:
    static RTTI* s_instance;
    std::map<std::string, createFunc> s_registeredClases;
};

RTTI* RTTI::s_instance = nullptr;

RTTI* RTTI::instance()
{
    if (!s_instance)
    {
        s_instance = new RTTI();
    }
    return s_instance;
}
void RTTI::registerClass(const std::string& className, createFunc instantiate)
{
    s_registeredClases.insert(std::make_pair (className, instantiate));
}
GameObject* RTTI::createGameObject(const std::string& className)
{
    return nullptr;
}

**#define PROTOTYPE_CREATE(BASE, CLASS) \
    static BASE* createInstance() { return new CLASS(); }**

#define PROTOTYPE_REGISTER(NAME, CLASS) \
    RTTI::instance()->registerClass(NAME, CLASS::createInstance);


//Player.h
class Player : public GameObject
{
public:
    //static GameObject* createInstance() { return new Player(); }
    PROTOTYPE_CREATE(GameObject, Player);
};
//Player.cpp

int _tmain(int argc, _TCHAR* argv[])
{
    PROTOTYPE_REGISTER("Player", Player)
    return 0;
}

【讨论】:

  • 有没有办法在cpp文件里面调用PROTOTYPE_REGISTER,其中Player类实现了,即://Player.cpp PROTOTYPE_REGISTER("Player", Player) Player::Player(){}
猜你喜欢
  • 2014-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-16
相关资源
最近更新 更多