用過java的開發者都知道,java有一種叫做反射的功能,可以根據類名來生成類的實例,這種機制的好處就是可以在不修改代碼的情況下,可以通過配制文件來決定生成什么類的對像。那么對於使用C++開的人來說,有沒有一種方式實現類似的功能呢?
雖然C++沒有從語言層面提供反射的機制,但是還是可以簡單的模擬出類似的功能的。在查找了很多資料,也看過很多人寫的不同實現后,將其中一種我認為模擬的比較好的方案做個總結。
首先定義一個ClassInfo類:
typedef Resource* (*ResourceConstructorFn)(void); class ClassInfo { public: ClassInfo(int type, ResourceConstructorFn creator):m_creator(creator) { Resource::regist(this); } Resource* create_resource() { return m_creator ? (*m_creator)() : 0; } ResourceConstructorFn m_creator; };
Resource類便是我們需要反射創建的類的基類了。定義如下:
class Resource { public: Resource(); virtual ~Resource() = 0; static Resource* get_resource(string name)
{
if(m_map_resource.find(name) != m_map_resource.end())
{
Resource* res = m_map_resource[name]->create_resource();
return res;
}
else
{
return NULL;
}
}
static void regist(ClassInfo* ci) { if(ci) { if(m_map_resource.find(ci->m_type) == m_map_resource.end()) { m_map_resource[ci->m_type] = ci; } } } protected: static std::map<string, ClassInfo*> m_map_resource; //資源類型與其類信息map,用於創建資源子類 };
ClassInfo類的構造函數里會將自身注冊到Resource基類當中,然后Resource類的get_resource(string name)函數就可以根據注冊的信息創建對應的Resource子類了。因此,我們只需讓所有Resource子類都有一個ClassInfo對像就行了。於是添加以下宏來實現:
//用於創建資源,所有繼承Resource類的子類,其定義結尾應當加此宏。 #define DECLARE_RESOURCE(class_name) \ private:\ static ClassInfo ci; \ public:\ ClassInfo* get_class_info(){return &ci;}\ static Resource* create_resource(){return new class_name();} //綁定資源及其類型,用於創建資源,所有繼承Resource類的子類,其實現中應當加此宏。 #define BIND_RESOURCE_TYPE(class_name, name) \ ClassInfo name::ci(name, (ResourceConstructorFn)&class_name::create_resource);
class A:Resouce
{
DECLARE_RESOURCE(A)
};
BIND_RESOURCE_TYPE(A, "A")
只要在擴展每個Resource的子類的時候,都加入DECLARE_RESOURCE和BIND_RESOURCE_TYPE這兩個宏,由於靜態變量會在程序執行最開始就初始化,也就是A類的ci成員會在一開始就將create_resource()函數注冊到Resource基類的m_map_resource中,
所以,要得到A類的實例,變只需要根據類名調用Resource::get_resource("A")即可。
雖然實現邏輯有點復雜,還需要在定義子類時加入兩個宏,但是還是可以模擬一下反射的功能的。