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

来源:http://www.cnblogs.com/YouJie/archive/2016/03/31/5333621.html
-Advertisement-
Play Games

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


  如何實現類型名跟類型的對應, 我們很容易想到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時保存下來的調試信息.當我發現這個時有點小興奮, 他解除了一個限制條件, 使得這種想法或許可以有更大的實用之處.

  

  最後再說點什麼:

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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 如果是對話框程式直接在對話框的 初始化時,修改樣式 ...
  • *從”http:localhost:8080”說起 “http://localhost:8080”是一個url.url的組成如下麵部分: *當你在瀏覽器地址欄中輸入”http:www.cdtu.com”按下回車之後, 為什麼出現成都工業學院首頁? 你收到的網頁是從伺服器來的, 呈現在現在瀏覽器中, ... ...
  • 在C中使用指針的原因 避免副本 在函數調用的時候,可以只傳遞數據的引用,而不用傳遞數據 數據共用 兩段代碼可以同時操作同一份數據,而不是兩份獨立的副本 使用指針讀寫數據 船長,向東航行! ...
  • 文章出自:聽雲博客 題主將以三個章節的篇幅來講解JAVA IO的內容 。 第一節JAVA IO包的框架體系和源碼分析,第二節,序列化反序列化和IO的設計模塊,第三節非同步IO。 本文是第一節。 IO框架 從上圖我們可以看出IO可以分為兩大塊 位元組流和字元流 位元組流是 InputStream 和 Out ...
  • 自己項目中使用到了 結果在不同的windows 操作系統中,程式的運行不一致,在windows server 2008上可以很好的運行,但是到了windows7上去卡死了!!!!!!!!!!!!!!!!!!!!!! p.waitFor() 卡死了或者報錯: 如果改為: 則直接卡死了。如果將 p.wa ...
  • 歷屆試題 核桃的數量 時間限制:1.0s 記憶體限制:256.0MB 時間限制:1.0s 記憶體限制:256.0MB 問題描述 小張是軟體項目經理,他帶領3個開發組。工期緊,今天都在加班呢。為鼓舞士氣,小張打算給每個組發一袋核桃(據傳言能補腦)。他的要求是: 1. 各組的核桃數量必須相同 2. 各組內必 ...
  • 廢話不多說,上來貼代碼最實在,哈哈! 以下代碼量有點多,不過這都是在下一手一手敲出來的,小巧好用,把以下代碼複製出來,放到相應的hpp文件即可,VS,GCC下均能編譯通過 接下來是traits庫的完整代碼 ...
  • 主題:構建一個基於SpringMVC的HelloWord Web 項目 目的:快速體驗什麼是SpringMVC 方案: 1、創建工程,命名:SpringMVC 2、導包 3、在SRC下添加spring-mvc.xml配置文件 (註意:名字可以隨便取,最好就是看上就知道是什麼) 4、在web.xml配 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...