A design & implementation of reflection in C++

Reflection in C++

前幾天看一個java演示的設計模式講解視頻,裏面提到了java中的反射機制,感覺反射這個東西很有意思,於是心血來潮想寫一個C++中的反射。

反射機制可以簡單地理解爲:當需要一個類型的實例時,根據類型的名稱就能得到一個實例。如下面的函數,

void* CreateClassInstance(const char *name);

這個函數可以根據傳入的類型名稱創建一個實例。

設計這樣一個系統,我們需要對類型的名稱和創建實例的方法(如構造函數)進行存儲。當然,函數的返回值最好有實際意義,而不是一個無意義的void*。我們給可以被反射的類型取名叫ReflectableClassReflectableClass作爲可被反射類型的基類。在這個class中需要對類型的名稱和創建實例的方法進行存儲,以便需要創建實例時可以進行查找。這裏我們用map存儲一個“鍵/值”對,“鍵”爲類型的名稱,“值”爲創建實例的方法。

static std::map<std::string, FUNC_CREATE_INSTANCE> s_reflectors;

FUNC_CREATE_INSTANCE的定義如下,它是一個函數指針,所指向的函數不帶參數。

typedef ReflectableClass* (*FUNC_CREATE_INSTANCE)();

這樣便有了如下的類型聲明:

class ReflectableClass

{

public:

    ReflectableClass() {}

    virtual ~ReflectableClass() {}

 

    virtual const char* GetClassName() = 0;

 

    static ReflectableClass* CreateClassInstance(const char* name);

    static bool AddInstanceCreator(const char*, FUNC_CREATE_INSTANCE);

 

private:

    static std::map<std::string, FUNC_CREATE_INSTANCE> s_reflectors;

};

GetClassName用來返回每種可被反射的類型的名稱,將其聲明爲純虛函數,因爲ReflectableClass被設計爲一個抽象的類型。

CreateClassInstance用來根據傳入的類型名稱創建並返回一個實例。

AddInstanceCreator用來註冊一個新類型。

當我們定義一個新的類型時,如定義一個Human類型,需要有種方式將類型的相關信息自動註冊到ReflectableClass中。我們可以爲新類型定義一個static的成員,在這個成員被初始化時將類型的信息註冊制ReflectableClass中。定義一個新的類ClassInfo來完成這個工作。

class ClassInfo

{

public:

    ClassInfo(const char* name, FUNC_CREATE_INSTANCE creator);

    ~ClassInfo();

};

 

ClassInfo::ClassInfo(const char* name, FUNC_CREATE_INSTANCE creator)

{

    ReflectableClass::AddInstanceCreator(name, creator);

}

 

ClassInfo::~ClassInfo()

{}

 

Human的定義如下:

class Human: public ReflectableClass

{

public:

    Human();

    virtual ~Human();

 

    virtual const char* GetClassName();

    static ReflectableClass* CreateInstance();

 

private:

    static ClassInfo s_classInfoHuman;

 

};

GetClassName是從ReflectableClass中繼承並override的虛函數。CreateInstance用來創建Human的實例,即一個FUNC_CREATE_INSTANCE指向的函數。s_classInfoHuman用來註冊Human的信息至ReflectableClass中。實現部分的代碼如下:

ClassInfo Human::s_classInfoHuman(“Human”, Human::CreateInstance);

 

const char* Human::GetClassName()

{

    return “Human”;

}

 

ReflectableClass* Human::CreateInstance()

{

    return new(std::nothrow) Human;

}

這樣我們就完成了一個Human的定義和註冊。當需要對Human進行反射時,只需調用“ReflectableClass::CreateClassInstance(“Human”)”即可。這裏需要注意一個問題,需確保“ReflectableClass:: s_reflectors”的初始化工作在“Human::s_classInfoHuman”初始化前完成,否則會產生問題。我們可以將ReflectableClassClassInfo的定義和實現放在一個動態連接庫中,當定義新類型時加載該庫文件。

爲方便在新類型中聲明和實現static ClassInfo的對象及GetClassNameCreateInstance兩個函數,可以定義一些自動化的宏。

完整的代碼如下:

ReflectableClass.h

ReflectableClass.cpp

Human.h

Human.cpp

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章