C++实现反射机制

C++本身是不支持反射机制的,而在最近项目中很多地方用到了工厂类,这样就增加了代码中分支语句,降低了代码的可读性,于是就模仿C#中的反射机制,用函数指针自己实现了C++的反射。下面是实现时写的demo介绍。

主要特点有以下几点:

  • 用map保存了字符串到动态类生成的函数指针的映射。
  • 使用类名注册,根据不同的类名字符串构造成不同的类对象。

代码实例: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;
    View Code

代码实例: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 };
    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             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 }
    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 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
    View Code

上述类型都是为反射动态创建类型准备的类,相当于是工具类,下面就是需要创建的动态类型的实例类介绍。

代码实例:Object类  是整个动态类型的基类,可有可无,在这里添加是为了方便扩展。

扫描二维码关注公众号,回复: 425144 查看本文章
  • 头文件
     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 };
    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 : public Object
     6 {
     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 : public Item
     5 {
     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 void FileItem::Print()
    17 {
    18     cout << className << endl;
    19 }
    View Code

代码实例: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 };
    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 void ConsoleItem::Print()
    17 {
    18     cout << className << endl;
    19 }
    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 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 }
    View Code

  该反射机制是每一次CreateItem就会创建一个新的类实例,所有使用完成后,需要我们手动调用delete来释放掉该类的实例。

 上述文件源码:https://download.csdn.net/download/qq123hongli/10405339

猜你喜欢

转载自www.cnblogs.com/qiuhongli/p/9019062.html
今日推荐