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