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

相關文章
相關標籤/搜索