C++自己是不支持反射機制的,而在最近項目中不少地方用到了工廠類,這樣就增長了代碼中分支語句,下降了代碼的可讀性,因而就模仿C#中的反射機制,用函數指針本身實現了C++的反射。下面是實現時寫的demo介紹。緩存
主要特色有如下幾點:ide
代碼實例:Singleton類函數
1 #pragma once 2 3 template<class T> 4 class Singleton 5 { 6 public: 7 using object_type = T; 8 struct object_creator 9 { 10 object_creator() { Singleton<T>::instance(); } 11 }; 12 13 static object_creator creator_object; 14 public: 15 static object_type* instance() 16 { 17 static object_type _instance; 18 return &_instance; 19 } 20 }; 21 template<typename T> typename Singleton<T>::object_creator Singleton<T>::creator_object;
代碼實例:ClassFactory類工具
1 #pragma once 2 #include "Singleton.h" 3 4 #include <map> 5 6 class Item; 7 8 //定義一個返回值爲void* 參數爲null的函數指針 9 typedef void* (*ItemObject)(); 10 11 struct ItemObjectClass 12 { 13 explicit ItemObjectClass(ItemObject item) : itemObject(item) {} 14 ItemObject itemObject; 15 }; 16 17 18 //做爲全部類的工廠,若有須要某一類型的類的工廠能夠繼承此類 19 class ClassFactory : public Singleton<ClassFactory> 20 { 21 public: 22 ClassFactory(); 23 ~ClassFactory(); 24 25 26 //************************************ 27 // Method: CreateItem 建立類, 28 // FullName: ClassFactory::CreateItem 29 // Access: public 30 // Returns: void * 31 // Qualifier: 32 // Parameter: string className 33 //************************************ 34 void * CreateItem(string className); // 返回void *減小了代碼的耦合 35 36 // 37 //************************************ 38 // Method: RegisterItem 39 // FullName: ClassFactory::RegisterItem 40 // Access: public 41 // Returns: void 42 // Qualifier: 43 // Parameter: const string & className 要建立類的類名 44 // Parameter: ItemObject item 函數指針,該指針在宏REGISTER_CLASS中被綁定 45 //************************************ 46 void RegisterItem(const string& className, ItemObject item); 47 48 private: 49 //緩存類名和生成類實例函數指針的map,ItemObject其實是一個函數指針 50 map<string, ItemObjectClass *> objectItems; 51 };
1 #include "stdafx.h" 2 #include "ClassFactory.h" 3 4 5 6 ClassFactory::ClassFactory() 7 { 8 } 9 10 11 ClassFactory::~ClassFactory() 12 { 13 for (auto it : objectItems) 14 { 15 if (it.second != nullptr) 16 { 17 delete it.second; 18 it.second = nullptr; 19 } 20 } 21 objectItems.clear(); 22 } 23 24 25 //返回void *減小了代碼的耦合 26 void * ClassFactory::CreateItem(string className) 27 { 28 ItemObject constructor = nullptr; 29 30 if (objectItems.find(className) != objectItems.end()) 31 constructor = objectItems.find(className)->second->itemObject; 32 33 if (constructor == nullptr) 34 return nullptr; 35 36 // 調用函數指針指向的函數 調用REGISTER_CLASS中宏的綁定函數,也就是運行new className代碼 37 return (*constructor)(); 38 } 39 40 //ItemObject至關於一個回掉函數 41 void ClassFactory::RegisterItem(const string& className, ItemObject item) 42 { 43 map<string, ItemObjectClass *>::iterator it = objectItems.find(className); 44 if (it != objectItems.end()) 45 objectItems[className]->itemObject = item; 46 else 47 objectItems.insert(make_pair(className, new ItemObjectClass(item))); 48 }
工廠類實例主要時用來生成每一個類的實例,該類的優勢是,編寫完成後,不須要改動,就能夠生成想要的類的實例(減小了增長或者刪除類時候要修改相應分支的代碼)。spa
代碼實例:REGISTERCLASS類 該類是一個宏定義,是爲了實現動態類型的建立.net
1 #pragma once 2 3 4 //該宏定義實現了一個動態類的建立, 5 // ## 合併操做符 將操做兩邊的字符合併成一個新的標識符,合併後新的標識符不是字符串 6 // # 構串操做符 它將實參的字符序列(而不是實參表明的值)轉換成字符串常量, 轉換後是一個字符串 7 // class className##Helper : 如className是FileItem,程序將會生成一個FileItemHelper類。 8 // 構造函數 : 調用工廠類的註冊函數,實現了類名和生成類實例函數的綁定 9 // CreatObjFunc函數 : 生成一個類實例 好比className是FileItem,則new FileItem. 返回void *減小了代碼的耦合 10 11 #define REGISTERCLASS(className) \ 12 class className##Helper { \ 13 public: \ 14 className##Helper() \ 15 { \ 16 ClassFactory::instance()->RegisterItem(#className, className##Helper::CreatObjFunc); \ 17 } \ 18 static void* CreatObjFunc() \ 19 { \ 20 return new className; \ 21 } \ 22 }; \ 23 className##Helper className##helper; 24 //定義了一個成員變量,如FileItemHelper類的成員變量 FileItemhelper
上述類型都是爲反射動態建立類型準備的類,至關因而工具類,下面就是須要建立的動態類型的實例類介紹。3d
代碼實例:Object類 是整個動態類型的基類,無關緊要,在這裏添加是爲了方便擴展。指針
1 #pragma once 2 3 //全部類的基類 4 class Object 5 { 6 public: 7 Object(); 8 virtual ~Object(); 9 10 const string& GetClassName() const { return className; } 11 12 protected: 13 string className; 14 };
1 #include "stdafx.h" 2 #include "Object.h" 3 4 5 Object::Object() 6 { 7 } 8 9 Object::~Object() 10 { 11 12 }
代碼實例:Item類 全部Item的基類code
1 #pragma once 2 #include "Object.h" 3 4 //全部Item的基類 5 class Item : public Object 6 { 7 public: 8 Item(); 9 virtual ~Item(); 10 11 virtual void Print() = 0; 12 13 };
1 #include "stdafx.h" 2 #include "Item.h" 3 4 5 Item::Item() 6 : Object() 7 { 8 } 9 10 11 Item::~Item() 12 { 13 }
該類是全部Item類型類的基類,下面將列舉FileItem和ConsoleItem做爲該類的派生類來具體實現和使用派生類的動態類型生成。對象
代碼實例:FileItem類
1 #pragma once 2 #include "Item.h" 3 4 class FileItem : public Item 5 { 6 public: 7 FileItem(); 8 ~FileItem(); 9 10 virtual void Print() override; 11 12 };
1 #include "stdafx.h" 2 #include "FileItem.h" 3 4 5 FileItem::FileItem() 6 : Item() 7 { 8 className = "FileItem"; 9 } 10 11 12 FileItem::~FileItem() 13 { 14 } 15 16 void FileItem::Print() 17 { 18 cout << className << endl; 19 }
代碼實例:ConsoleItem類
1 #pragma once 2 #include "Item.h" 3 4 class ConsoleItem : public Item 5 { 6 public: 7 ConsoleItem(); 8 ~ConsoleItem(); 9 10 virtual void Print() override; 11 12 };
1 #include "stdafx.h" 2 #include "ConsoleItem.h" 3 4 5 ConsoleItem::ConsoleItem() 6 : Item() 7 { 8 className = "ConsoleItem"; 9 } 10 11 12 ConsoleItem::~ConsoleItem() 13 { 14 } 15 16 void ConsoleItem::Print() 17 { 18 cout << className << endl; 19 }
到此爲止,使用單例,工廠和函數指針來完成的反射機制已完成,如今就是怎麼來使用該反射機制。那麼在main函數中將會給出使用實例:
1 // main.cpp: 定義控制檯應用程序的入口點。 2 // 3 4 #include "stdafx.h" 5 6 #include "ClassFactory.h" 7 #include "FileItem.h" 8 #include "ConsoleItem.h" 9 #include "REGISTERCLASS.h" 10 11 //類型註冊,必須註冊才能使用,不註冊降不會動態生成須要的類的實例 12 REGISTERCLASS(FileItem) 13 REGISTERCLASS(ConsoleItem) 14 15 16 int main() 17 { 18 FileItem* fileItem = static_cast<FileItem *>(ClassFactory::instance()->CreateItem("FileItem")); 19 fileItem->Print(); 20 delete fileItem; 21 22 ConsoleItem* consoleItem = static_cast<ConsoleItem *>(ClassFactory::instance()->CreateItem("ConsoleItem")); 23 consoleItem->Print(); 24 delete consoleItem; 25 26 return 0; 27 }
該反射機制是每一次CreateItem就會建立一個新的類實例,全部使用完成後,須要咱們手動調用delete來釋放掉該類的實例。
上述文件源碼:https://download.csdn.net/download/qq123hongli/10405339