标签:构造 print creat ext nullptr ## static 完成 UNC
C++本身是不支持反射机制的,而在最近项目中很多地方用到了工厂类,这样就增加了代码中分支语句,降低了代码的可读性,于是就模仿C#中的反射机制,用函数指针自己实现了C++的反射。下面是实现时写的demo介绍。
主要特点有以下几点:
代码实例: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 }
工厂类实例主要时用来生成每个类的实例,该类的优点是,编写完成后,不需要改动,就可以生成想要的类的实例(减少了增加或者删除类时候要修改相应分支的代码)。
代码实例:REGISTERCLASS类 该类是一个宏定义,是为了实现动态类型的创建
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
上述类型都是为反射动态创建类型准备的类,相当于是工具类,下面就是需要创建的动态类型的实例类介绍。
代码实例: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的基类
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
标签:构造 print creat ext nullptr ## static 完成 UNC
原文地址:https://www.cnblogs.com/qiuhongli/p/9019062.html