【问题标题】:Extensible way to make class information accessible at runtime使类信息在运行时可访问的可扩展方式
【发布时间】:2012-03-17 06:27:31
【问题描述】:

我正在制作一个简单的消息传递实体系统。我有一个实体描述符表连接到一个工厂,用于在运行时创建实体子类,我想拥有它,以便可以通过字符串创建它们:

EntityManager manager; //managers have all of the entity table information (See below)

//Counter is a sample class that inherits from Entity
Counter* counter = manager.makeEntity("Counter"); //the string doesn't have to match the class name.

现在,我知道我可以使用简单的 switch 语句,但我希望系统也可以扩展——也就是说,当我(或我系统的其他用户)想要创建一个新的 Entity 子类时,我不会不必去开关块并添加它。目前,我使用宏来创建静态实例化的辅助类,以便构造函数将条目添加到实体表。这些类还初始化实体并从构造函数中删除大量样板。

//EHandle is a wrapper for Entity*. Currently std::shared_ptr<Entity>

class GenericDesc
{
public:
virtual ~GenericDesc() {}
    virtual EHandle makeEntity() const =0;
};

namespace Descriptor
{
    //Adds a descriptor to an internal map<string, GenericDesc*>
    void addEntityDescriptor(const std::string& type, GenericDesc& desc);
    EHandle newEntity(const std::string& type); //Factory method
}

//Add this to every entity class definition
#define DECLARE_ENTITY_CLASS(CLASS_NAME) \
    friend class CLASS_NAME##Descriptor;


//Use these after a class definition to add the entity class to the descriptor table
#define BEGIN_ENTITY_TYPE(ENTITY_NAME, CLASS_NAME, BASE_NAME) \
    BEGIN_ENTITY_TYPE_GUTS(ENTITY_NAME, CLASS_NAME) \
        BASE_NAME##Descriptor::prepareEntity(ent);

#define BEGIN_ENTITY_TYPE_BASELESS(ENTITY_NAME, CLASS_NAME) \
    BEGIN_ENTITY_TYPE_GUTS(ENTITY_NAME, CLASS_NAME) \
        ent->self = ent;

#define BEGIN_ENTITY_TYPE_GUTS(ENTITY_NAME, CLASS_NAME) \
class CLASS_NAME##Descriptor : public GenericDesc \
{ \
private: \
    typedef CLASS_NAME ClassName; \
public: \
    CLASS_NAME##Descriptor() \
    { \
        Descriptor::addEntityDescriptor(ENTITY_NAME, *this); \
    } \
    virtual ~CLASS_NAME##Descriptor() {} \
    virtual EHandle makeEntity() const\
    { \
        auto ent = std::shared_ptr<CLASS_NAME>(new CLASS_NAME); \
        prepareEntity(ent); \
        ent->type = ENTITY_NAME; \
        return ent; \
    } \
    static void prepareEntity(std::shared_ptr<ClassName> ent) \
    {

//These functions are caled between BEGIN_ENTITY_TYPE and END_ENTITY_TYPE
//ADD_ENTITY_INPUT binds a function to a string
#define ADD_ENTITY_INPUT(INPUT_NAME, INPUT_FUNC) \
        ent->addInput(INPUT_NAME, std::bind(&ClassName::INPUT_FUNC, ent, std::placeholders::_1));
//ADD_ENTITY_OUTPUT binds an Output object to a string
#define ADD_ENTITY_OUTPUT(OUTPUT_NAME, OUTPUT_OBJECT) \
        ent->addOutput(OUTPUT_NAME, ent->OUTPUT_OBJECT);

#define END_ENTITY_TYPE(CLASS_NAME) \
    } \
}; \
static CLASS_NAME##Descriptor CLASS_NAME##Desc; //TODO: find a way to fix the multiple-static-allocation issue

这个想法是您创建一个 BEGIN_ENTITY_TYPE(...) END_ENTITY_TYPE(...) 子句,中间有 ADD_ENTITY_x 位。我的问题是是否有一种不那么宏观的方法来做到这一点,它仍然可以最大限度地减少样板文件,并且不需要修改定义实体子类的文件之外的任何文件。模板类可以工作,但我不知道如何使用模板类执行 ADD_ENTITY_INPUT/OUTPUT 的工作。

【问题讨论】:

    标签: c++ factory-pattern


    【解决方案1】:

    这可能不完全是您所追求的,但请考虑以下内容:

    class Factory
    {
    public:
        virtual void InitialiseFactory() = 0;
        Entity* CreateEntity( string type )
        {
            // (obviously, you must handle the string not being found.)
            return m_MapEntities[ type ]->Clone();
        }
    };
    
    class MyFactory : public Factory
    {
    public:
        void InitialiseFactory()
        {
            m_MapEntities["typea"] = new MyEntity();
        } 
    };
    

    这里的想法是查找在基类中具体化,可以保持不变,但提供实体的细节在派生类的实现中。

    另一种方法是在每个实体中添加一个调用工厂的静态方法,但仍需要从某个地方调用该方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-19
      • 1970-01-01
      • 1970-01-01
      • 2011-09-27
      • 2012-07-19
      • 1970-01-01
      • 1970-01-01
      • 2019-11-02
      相关资源
      最近更新 更多