• 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类  是整个动态类型的基类,可有可无,在这里添加是为了方便扩展。

    • 头文件
       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

  • 相关阅读:
    wxpython 文本框TextCtrl
    python py文件转换成exe
    安装NTP到CentOS(YUM)
    安装NFS到CentOS(YUM)
    安装MongoDB到Ubuntu(APT)
    安装MongoDB到CentOS(YUM)
    安装Mailx到CentOS(YUM)
    安装MYSQL到Ubuntu(APT)
    安装MYSQL到CentOS(YUM)
    安装Kubernetes到CentOS(Minikube)
  • 原文地址:https://www.cnblogs.com/qiuhongli/p/9019062.html
Copyright © 2020-2023  润新知