2012-02-27 5 views
4

私は単純なメッセージパッシングエンティティシステムを作っています。私は、単純なswitch文することができます知っている、クラス情報を実行時にアクセス可能にする拡張可能な方法

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. 

:私は、実行時にエンティティのサブクラスを作成するための工場にフックエンティティ記述子テーブルを持っている、と私は、彼らが文字列で作成することができるので、それを持ってしたいと思います私のシステムの他のユーザが新しい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 

アイデアは、あなたが途中でADD_ENTITY_xビットでBEGIN_ENTITY_TYPE(...)END_ENTITY_TYPE(...)節を作成することです。私の質問は、これを行うマクロ的ではない方法があるかどうかです。それでも、定型文は最小限に抑えられ、Entityサブクラスを定義するファイル以外のファイルは変更する必要がありません。テンプレートクラスはうまくいくかもしれませんが、テンプレートクラスを使ってADD_ENTITY_INPUT/OUTPUTをどうやってやるのか分かりません。

答えて

0

これはあなたが後にしているものを完全にすることが、のようなものを考慮しない場合があります

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(); 
    } 
}; 

ここでの考え方ルックアップが変わらないことができ、基本クラスにconcretisedされていることですが、の詳細エンティティは、派生クラスの実装にあります。

もう1つの方法は、各エンティティで、追加するファクトリを呼び出す静的メソッドですが、そのメソッドはまだどこかから呼び出す必要があります。

+0

テンプレートを使用している: – Lucretiel

+0

これは質問ですか? :-) –

関連する問題