C++ 反射機制詳解及實例代碼。本站提示廣大學習愛好者:(C++ 反射機制詳解及實例代碼)文章只能為提供參考,不一定能成為您想要的結果。以下是C++ 反射機制詳解及實例代碼正文
C++ 反射機制
一.前言:
Java有著一個十分突出的靜態相關機制:Reflection,用在Java身上指的是我們可以於運轉時加載、探知、運用編譯時期完全未知的classes。換句話說,Java順序可以加載一個運轉時才得知稱號的class,得悉其完好結構(但不包括methods定義),並生成其對象實體、或對其fields設值、或喚起其methods。但是C++是不支持反射機制,雖然C++有RTTI(運轉時類型辨認)。但是想要完成C++對象序列化,序列化就是存儲到磁盤上,將對象變成一定格式的二進制編碼,然後要用的時分再將保管在磁盤上的二進制編碼轉化成一個內存中的對象,這個進程中總是需求有一個指示來通知編譯器要生成什麼樣的對象,最復雜的方式當然就是類名了,例如:將一個ClassXXX對象存儲到磁盤上,再從磁盤讀取的時分讓編譯器依據“ClassXXX”稱號來new一個對象。
ClassT* obj = FactoryCreate("ClassT");
相似於以上的語法,雖然C++沒有自帶的語法可以完成,但是我們可以自己經過其他辦法來完成。(由於自己才能無限,所以該篇博客只是解說如何復雜的完成這個反射機制,而對C++中擁有這個反射機制能否有必要不做任何討論。當然,假如博客中有什麼中央說的有錯誤還望大家可以在上面評論指出謝謝)
二.完成:
1.我們很容易可以想到可以運用復雜工廠形式來完成這個效果:比方
class Object { public: virtual string ToString() = 0; };
這個是一切需求完成反射機制的類需求承繼的基類,然後派生出來的類只需求再完成這個ToString即可。例如:
class MyClass :public Object { public: virtual string ToString(){ return "MyClass"; } };
然後就是用於發生對象的工廠。
Object* FactoryCreat(const string& className) { if (className == "ClassA") return new ClassA; else if (className == "ClassB") return new ClassB; else if(className == "ClassC") return new ClassC; else if(className == "ClassD") return new ClassD; else if(className == "ClassE") return new ClassE; ... }
我們運用就可以這樣:
int main() { Object* obj = FactoryCreat("MyClass"); cout << obj->ToString(); delete obj; return 0; }
我們運用復雜工廠形式覺得仿佛是處理了問題,可以完成用字符串去new一個對應的對象,但是假設我們要新建一個類或許修正一個類,那麼這個FactoryCreat都要停止修正。非常不利於維護。所以我們需求換一個方式來處置。
2.工廠形式結合回調機制。
首先我們要梳理一下這個辦法的根本頭緒:
1.工廠外部需求有個映射,也就是一個字符串對應一個類new的辦法。
2.工廠給出一個接口,我們傳入字符串,那麼前往這個字符串對應的辦法new出來的對象指針。
3.我們新建的類,假如需求支持反射機制,那麼這個類需求自動將自己的new辦法和名字注冊到工廠的映射中。
OK,假如我們能完成以上幾個要求,那麼我們在類停止拓展的時分需求改動的中央就非常少了。關於工廠的代碼我們根本上是不會改動的。也就根本上完成了我們C++反射機制的根本功用。
上面我們來一步一步解析代碼:
首先我們還是需求一個Object作為需求支持反射機制類的基類
//Reflex.h class Object { public: Object(){} virtual ~Object(){} static bool Register(ClassInfo* ci); //注冊傳入一個classInfo(類信息),將這個類的信息注冊到映射中 static Object* CreateObject(string name); //工廠消費對象的接口 };
然後是完成:
//Reflex.cpp static std::map< string, ClassInfo*> *classInfoMap = NULL; bool Object::Register(ClassInfo* ci) { if (!classInfoMap) { classInfoMap = new std::map< string, ClassInfo*>(); //這裡我們是經過map來存儲這個映射的。 } if (ci) { if (classInfoMap->find(ci->m_className) == classInfoMap->end()){ classInfoMap->insert(std::map< string, ClassInfo*>::value_type(ci->m_className, ci)); // 類名 <-> classInfo } } return true; } Object* Object::CreateObject(std::string name) { std::map< string, ClassInfo*>::const_iterator iter = classInfoMap->find(name); if (classInfoMap->end() != iter) { return iter->second->CreateObject(); //當傳入字符串name後,經過name找到info,然後調用對應的CreatObject()即可 } return NULL; }
剩下的我們還需求一個classinfo類就半途而廢了:
//Reflex.h typedef Object* (*ObjectConstructorFn)(void); class ClassInfo { public: ClassInfo(const std::string className, ObjectConstructorFn ctor) :m_className(className), m_objectConstructor(ctor) { Object::Register(this); //classInfo的結構函數是傳入類名和類對應的new函數然後自動注冊進map中。 } virtual ~ClassInfo(){} Object* CreateObject()const { return m_objectConstructor ? (*m_objectConstructor)() : 0; } bool IsDynamic()const { return NULL != m_objectConstructor; } const std::string GetClassName()const { return m_className; } ObjectConstructorFn GetConstructor()const{ return m_objectConstructor; } public: string m_className; ObjectConstructorFn m_objectConstructor; };
有了這些類後,我們只需求讓需求支持反射的類滿足以下要求即可:
1.承繼Object類。
2.重載一個CreatObject()函數,外面 return new 本身類。
3.擁有一個classInfo的成員並且用類名和CreatObject初始化。
滿足以上三個要求的類我們就可以應用反射機制來創立對象了。我們可以看上面的例子:
class B : public Object { public: B(){ cout << hex << (long)this << " B constructor!" << endl; } ~B(){ cout << hex << (long)this << " B destructor!" << endl; } virtual ClassInfo* GetClassInfo() const{ return &ms_classinfo; } static Object* CreateObject() { return new B; } protected: static ClassInfo ms_classinfo; }; ClassInfo B::ms_classinfo("B", B::CreateObject);
運用的話我們就只需求調用Object::CreatObject(string) 傳入類名即可。
int main() { Object* obj = Object::CreateObject("B"); delete obj; return 0; }
根本上反射機制的功用就完成了,而且運用回調注冊在前期拓展上也容易維護。
三.運用宏簡化代碼:
其實大家發現,由於我們要讓類支持反射那麼就要滿足我們下面的那三個要求,但是每個類都要寫這樣類似的東西。細心一看,包括函數申da's明、函數定義、函數注冊,每個類的代碼除了類名外其它都是如出一轍的,有沒有復雜的辦法呢?
那就是運用宏。
//Reflex.h //類聲明中添加 classInfo 屬性 和 CreatObject、GetClassInfo 辦法 #define DECLARE_CLASS(name) \ protected: \ static ClassInfo ms_classinfo; \ public: \ virtual ClassInfo* GetClassInfo() const; \ static Object* CreateObject(); //完成CreatObject 和 GetClassInfo 的兩個辦法 #define IMPLEMENT_CLASS_COMMON(name,func) \ ClassInfo name::ms_classinfo((#name), \ (ObjectConstructorFn) func); \ \ ClassInfo *name::GetClassInfo() const \ {return &name::ms_classinfo;} //classInfo 屬性的初始化 #define IMPLEMENT_CLASS(name) \ IMPLEMENT_CLASS_COMMON(name,name::CreateObject) \ Object* name::CreateObject() \ { return new name;}
有了宏交換後,我們定義一個新的類。
只需求在類定義中添加 DECLARE_CLASS(classname) 完成中添加IMPLEMENT_CLASS(classname)就可以讓這個類完成反射了。
例如我們下面的類B就可以這樣寫:
class B : public Object { DECLARE_CLASS(B) public: B(){ cout << hex << (long)this << " B constructor!" << endl; } ~B(){ cout << hex << (long)this << " B destructor!" << endl; } }; IMPLEMENT_CLASS(B)
這樣不論當前需求添加、修正什麼功用都只需求修正宏就可以了而不需求每個類每個類去添加、修正辦法。
ok到這裡根本上,c++反射機制的完成就半途而廢了!。
感激閱讀,希望能協助到大家,謝謝大家對本站的支持!