C++实现反射机制

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

主要特色有如下几点:ide

  • 用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

 

工厂类实例主要时用来生成每一个类的实例,该类的优势是,编写完成后,不须要改动,就能够生成想要的类的实例(减小了增长或者删除类时候要修改相应分支的代码)。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
    View Code

 

上述类型都是为反射动态建立类型准备的类,至关因而工具类,下面就是须要建立的动态类型的实例类介绍。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 };
    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的基类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 };
    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

相关文章
相关标签/搜索