1. 問題提出:
C++ RTTI缺乏一些運行時信息,無法根據對象名直接創建對象。所以MFC爲了實現序列化,從頭構造了自己的RTTI信息,並定義了一整套宏。具體可以參考MFC源代中一下類和宏的實現:
CRuntimeClass, CObject, DECLARE_DYNAMIC, IMPLEMENT_DYNAMIC
2. 需求:
個人正在寫一個做集成測試的工具,有一個配置文件,用於指定哪些CASE需要被測試到,內容大致如下:
<ut>
<case name="case1"/>
<case name="case2"/>
</ut>
當測試工具導入該配置信息時候,必須能夠根據 “case1", "case2"等名字創建相應的Case對象。顯然C++沒有提供類似的功能。
3. 實現:
仿照MFC Serialize的實現,定義一個基類和2個宏。需要被動態創建的對象從該基類派生,並使用2個宏註冊到對象工廠,然後就可以使用對象工廠根據對象名創建該對象。
基類和宏的定義:
class CUTObject
{
public:
virtual ~CUTObject(){}
virtual void SetUTName(CFString name);
virtual CFString GetUTName();
virtual CUTObject* Clone(){ return NULL; }
private:
CFString m_strUTName;
};
#define DECLARE_UTOBJECT(className) /
public: /
virtual CUTObject* Clone() /
{ return new className(); } /
static CUTObject* CreateObject() /
{ return new className(); } /
static bool RegisterObject(CFString utName) /
{ /
className *pObj = (className*)CreateObject(); /
CUTFactory *pFactory = CUTFactory::Instance(); /
pFactory->RegisterObject(utName, pObj); /
return true; /
} /
#define REGISTER_UTOBJECT(utName, className) bool b##className = className::RegisterObject(utName);
CUTFactory是一個的Singletion對象,提供2個方法:RegisterObject和CreateObject:
class CUTFactory
{
public:
static CUTFactory* Instance();
private:
CUTFactory();
CUTFactory(const CUTFactory& other){}
CUTFactory& operator=(const CUTFactory& other){}
public:
bool RegisterObject(CFString name, CUTObject *pObj);
CUTObject* CreateObject(CFString name);
private:
static CUTFactory* m_pInstance;
static std::map<CFString, CUTObject*> m_mapObjects;
};
4. 關鍵點:
最關鍵的代碼是
#define REGISTER_UTOBJECT(utName, className) bool b##className = className::RegisterObject(utName);
這行代碼被調用時,對象className將會以utName的名字註冊到對象工廠 。實際上是調用className::RegisiterObject方法。創建一個className的實例,然後將該實例放置到Factory的數組中。因爲DECLARE_UTOBJECT宏爲每個對象定義了Clone方法,所以類工廠可以從該數組中的實例來創建該對象的其他實例。
至於REGISTER_UTOBJECT爲什麼要定義一個bool b##className對象,完全是因爲這樣寫才能通過編譯器檢查。編譯器讀到className::RegisterObejct(utName)時候,會認爲這是在進行一個函數定義,而不是進行一個函數調用。只有明確指定返回值的情況下,才被認爲是函數調用。