程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 一種實現C++反射功能的想法(三),想法

一種實現C++反射功能的想法(三),想法

編輯:C++入門知識

一種實現C++反射功能的想法(三),想法


  如何實現類型名跟類型的對應, 我們很容易想到map, 沒錯, 就是使用map實現的. std::map<std::string, .....>, 等下, 第二部分該填什麼類型, 一個函數指針, auto create()? auto只是占位符, 編譯器好像不會讓你通過吧. 我們需要一種容器, 可以存放所有的類型,  模板. 

  由於聲明這個容器是並不能包含模板參數, 這裡借鑒了boost 庫中any的代碼, 原理如下:

 1 class Container {
 2 
 3 private:
 4 
 5     class bridge {
 6 
 7     public:
 8         bridge(){}
 9         virtual ~bridge(){}
10         virtual void invoke(unsigned long long addr, const std::vector<const char*>& args) = 0;
11         virtual void* instanceOfClass() = 0;
12     };
13 
14     template<typename ValueType>
15     class holder: public bridge {
16 
17     public:
18         virtual void invoke(unsigned long long addr, const std::vector<const char*>& args) override{};
19         virtual void* instanceOfClass() override{};
20     };
21 
22     template<typename ValueType>
23     class holder<ValueType*>: public bridge {
24 
25     public:
26         holder(ValueType* item){}
27         virtual ~holder() {}
28 
29         virtual void invoke(unsigned long long addr, const std::vector<const char*>& args) override{
30 
31         }
32         
33         virtual void* instanceOfClass() override{
34 
35         
36
37 } 38 }; 39 40 bridge* content_; 41 public: 42 Container(){} 43 ~Container(){ 44 Alloc::dellocate(content_); 45 } 46 47 template<typename ValueType> 48 Container(ValueType* item) { 49 50 holder<ValueType*>* h = static_cast<holder<ValueType*>*>(Alloc::allocate(sizeof(holder<ValueType*>))); 51 new(h) holder<ValueType*>(item); 52 content_ = h; 53 } 54 55 // three arguments most, and type are char* 56 void invoke(unsigned long long addr, const std::vector<const char*>& args) { 57 58 content_->invoke(addr, args); 59 } 60 61 void* instanceOfClass() { 62 63 return content_->instanceOfClass(); 64 } 65 66 };

  Container只是一層包裝, 隱藏了模板參數, 真正存儲類型的是繼承bridge的holder子類, bridge提供接口, 由於純虛函數不能是模板函數, 所以返回實例是必須強制轉型為void* 指針, 由客戶端再強制轉型回來.如何存儲一個類類型的信息呢, 最簡單, 保存該類型的一個指針變量就行. 其他的交由編譯器的模板處理. 然後將類注冊, 即插入map中. 可以通過宏來實現.

  好了, 到了最後一步, 函數類型問題. 我們的目標是在配置文件中聲明類似的語句:

  <Function name="declation", scale = "Init">

    <Argument>One</Argument>

    <Argument>Two</Argument>

  </Function>

  只要這樣聲明就能生產 void declation(const Init*, One, Two)這樣的函數聲明. 

  由於文本中只能保存基本的類型, 你不可能用在文本中指定某個參數是指針吧. 還有是函數個數的問題, 我本以為模板的可變參數能起點作用, 結果發現並不是我想要的. 好吧, 所以只能再做一個限制條件, 3個參數最多, 如果你寫的函數參數多余三個, 我想你肯定有辦法減少參數個數的, 還有參數類型都是字符串, 從字符串到其他基本類型的轉換必須由函數自己解決. 這樣, 解決思路很清晰了, 首先根據scale類型獲取容器, 根據函數名獲取地址, 根據參數個數獲取函數類型, 最後執行.

  所有的源代碼我都上傳在github上面, reflect

 

  補充:

  之前我一直以為該實現反射的方式只能在debug下才有效, 應為debug下編譯器會玩可執行文件中加入大量的調試信息, 當使用release版本時, 並沒有這些編譯信息, 或許可以使用之前保存過的信息, 但可能會對內存地址有所影響. 之後我詳細了解了elf文件格式後, 發現並不會影響, 至少我目前的測試是沒有影響的. debug時是將調試信息以dwarf格式的段添加到可執行文件後, 而並不是隨機穿插在程序中, 所以只有release時代碼並沒有修改, 注意宏的修改, 就可以使用debug時保存下來的調試信息.當我發現這個時有點小興奮, 他解除了一個限制條件, 使得這種想法或許可以有更大的實用之處.

  

  最後再說點什麼:

  這是自己第一次寫博客, 自從上了大學以後, 沒學過語文, 以前並不知道語文是這麼重要, 直達現在發現自己並不能將自己想要說的流暢地, 有層次地表達出來, 寫下來. 這幾篇博客修修補補還是花了自己一點時間. 如果你在看完之後, 笑道這都寫了寫什麼東西啊, 我也並不會介意的. 以前是懶與去經營自己的博客, 當發現自己寫出屬於自己的博客時, 還是挺有滿足感的, 我也會繼續寫下去, 繼續鍛煉, 或許多年以後翻翻自己寫過的東西, 回信一下自己當時的所思所想, 也將是已將很有趣的事情吧.

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved