概述
C++本身是不支持反射机制的,而在最近项目中很多地方用到了工厂类,这样就增加了代码中分支语句,降低了代码的可读性,于是就模仿C#中的反射机制,用函数指针自己实现了C++的反射。下面是实现时写的demo介绍。
主要特点有以下几点:
用map保存了字符串到动态类生成的函数指针的映射。
使用类名注册,根据不同的类名字符串构造成不同的类对象。
代码实例:Singleton类
头文件
1 #pragma once
2
3 template
4 classSingleton5 {6 public:7 using object_type =T;8 structobject_creator9 {10 object_creator() { Singleton::instance(); }11 };12
13 staticobject_creator creator_object;14 public:15 static object_type*instance()16 {17 staticobject_type _instance;18 return &_instance;19 }20 };21 template typename Singleton::object_creator Singleton::creator_object;
View Code
代码实例:ClassFactory类
头文件
1 #pragma once
2 #include "Singleton.h"
3
4 #include
5
6 classItem;7
8 //定义一个返回值为void* 参数为null的函数指针
9 typedef void* (*ItemObject)();10
11 structItemObjectClass12 {13 explicitItemObjectClass(ItemObject item) : itemObject(item) {}14 ItemObject itemObject;15 };16
17
18 //作为所有类的工厂,如有需要某一类型的类的工厂可以继承此类
19 class ClassFactory : public Singleton
20 {21 public:22 ClassFactory();23 ~ClassFactory();24
25
26 //************************************27 //Method: CreateItem 创建类,28 //FullName: ClassFactory::CreateItem29 //Access: public30 //Returns: void *31 //Qualifier:32 //Parameter: string className33 //************************************
34 void * CreateItem(string className); //返回void *减少了代码的耦合35
36 //
37 //************************************38 //Method: RegisterItem39 //FullName: ClassFactory::RegisterItem40 //Access: public41 //Returns: void42 //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 mapobjectItems;51 };
View Code
源文件
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 deleteit.second;18 it.second =nullptr;19 }20 }21 objectItems.clear();22 }23
24
25 //返回void *减少了代码的耦合
26 void * ClassFactory::CreateItem(stringclassName)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 returnnullptr;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::iterator it =objectItems.find(className);44 if (it !=objectItems.end())45 objectItems[className]->itemObject =item;46 else
47 objectItems.insert(make_pair(className, newItemObjectClass(item)));48 }
View Code
工厂类实例主要时用来生成每个类的实例,该类的优点是,编写完成后,不需要改动,就可以生成想要的类的实例(减少了增加或者删除类时候要修改相应分支的代码)。
代码实例: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 classclassName##Helper { 13 public: 14 className##Helper() 15 { 16 ClassFactory::instance()->RegisterItem(#className, className##Helper::CreatObjFunc); 17 } 18 static void*CreatObjFunc() 19 { 20 return newclassName; 21 } 22 }; 23 className##Helper className##helper;24 //定义了一个成员变量,如FileItemHelper类的成员变量 FileItemhelper
View Code
上述类型都是为反射动态创建类型准备的类,相当于是工具类,下面就是需要创建的动态类型的实例类介绍。
代码实例:Object类 是整个动态类型的基类,可有可无,在这里添加是为了方便扩展。
头文件
1 #pragma once
2
3 //所有类的基类
4 classObject5 {6 public:7 Object();8 virtual ~Object();9
10 const string& GetClassName() const { returnclassName; }11
12 protected:13 stringclassName;14 };
View Code
源文件
1 #include "stdafx.h"
2 #include "Object.h"
3
4
5 Object::Object()6 {7 }8
9 Object::~Object()10 {11
12 }
View Code
代码实例:Item类 所有Item的基类
头文件
1 #pragma once
2 #include "Object.h"
3
4 //所有Item的基类
5 class Item : publicObject6 {7 public:8 Item();9 virtual ~Item();10
11 virtual void Print() = 0;12
13 };
View Code
源文件
1 #include "stdafx.h"
2 #include "Item.h"
3
4
5 Item::Item()6 : Object()7 {8 }9
10
11 Item::~Item()12 {13 }
View Code
该类是所有Item类型类的基类,下面将列举FileItem和ConsoleItem作为该类的派生类来具体实现和使用派生类的动态类型生成。
代码实例:FileItem类
头文件
1 #pragma once
2 #include "Item.h"
3
4 class FileItem : publicItem5 {6 public:7 FileItem();8 ~FileItem();9
10 virtual void Print() override;11
12 };
View Code
源文件
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 voidFileItem::Print()17 {18 cout << className <
View Code
代码实例:ConsoleItem类
头文件
1 #pragma once
2 #include "Item.h"
3
4 class ConsoleItem : publicItem5 {6 public:7 ConsoleItem();8 ~ConsoleItem();9
10 virtual void Print() override;11
12 };
View Code
源文件
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 voidConsoleItem::Print()17 {18 cout << className <
View Code
到此为止,使用单例,工厂和函数指针来完成的反射机制已完成,现在就是怎么来使用该反射机制。那么在main函数中将会给出使用实例:
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 intmain()17 {18 FileItem* fileItem = static_cast(ClassFactory::instance()->CreateItem("FileItem"));19 fileItem->Print();20 deletefileItem;21
22 ConsoleItem* consoleItem = static_cast(ClassFactory::instance()->CreateItem("ConsoleItem"));23 consoleItem->Print();24 deleteconsoleItem;25
26 return 0;27 }
View Code
该反射机制是每一次CreateItem就会创建一个新的类实例,所有使用完成后,需要我们手动调用delete来释放掉该类的实例。
最后
以上就是妩媚银耳汤为你收集整理的c++ so 反射_C++实现反射机制的全部内容,希望文章能够帮你解决c++ so 反射_C++实现反射机制所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复