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


  Java的反射機制很酷, 只需知道類的名字就能夠加載調用. 這個功能很實用, 想象一下, 用戶只需指定類的名稱, 就可以動態綁定類型, 而且只需通過字符串指定, 字符串的使用可以使得用戶的修改只需修改一個配置文件就行, 僅僅修改配置文件, 連重新編譯都不需要. 喔噢噢, 這種做法將代碼的解耦程度做到了極致, 這種技術也不是什么新技術, spring, struct, hibernate......大多數框架都使用到java的反射機制, 而且是作為核心技術, 如果你還未了解反射的話, 趕緊抓緊時間吧.

  有這么一句話, "機器碼生匯編, 匯編生C, C生萬物...". 同為重量級的編程語言的C/C++有沒有類似的反射機制呢? 很遺憾, C++的語法並沒有. 首先, 讓我們先整理一下C++ 跟 java的區別:

 

  我對java不熟悉, 所以我大致是這樣理解java 實現反射的機制: jvm 在解釋執行.class文件時, 遇到了使用反射的字節碼, 於是類加載器加載相應的.class, jvm跳到特定的地方繼續執行.如果有錯誤, 還請大家指正. 而C++不同, C++將源程序直接編譯成可執行文件, 一般這個可執行文件是不可改變的. 一旦編譯完成后, 想要再修改程序, 就必須重新編譯.

  那么C++能不能實現類似java的反射呢? 這是個很有吸引力的問題, 大把大把的人在探索解決方案.

  (一) 從根本上解決就是修改編譯器, 當編譯器掃描到使用反射的語句時生成特定的機器碼, 程序執行時能正確跳躍到相應的位置. 聽起來跟java原理很像, 還是有點區別的. 這個方案需要解決兩個問題, 一是類的序列化問題, 二是編譯器的問題. 這兩個都不是簡單的問題.

  (二) 或許我們將標准放低一點, 實現偽反射就行. 從編程角度上解決問題, 這是比較現實的做法, 不少人提出了各式各樣的解決方案:

  1. 使用map 將類名跟類產生器對應起來, 類擴展通過動態鏈接庫來做, 缺點是擴展時必須重新鏈接, 不過相對於重新編譯已經提高了一個層次.

  2. 使用類似注解的方法, 編譯的時候先將注解的地方換成C++語句, 在調用C++編譯器編譯. 缺點是不能做擴展, 擴展必須重新編譯.

  

  我的做法也是對上面兩種方法的小修小部而已, 不過我還實現了函數的反射功能, 先上demo

  類類型:

 1 class Sharp {
 2 
 3 public:
 4     virtual void say()  =0 ;
 5 
 6 };
 7 
 8 class Point: public Sharp {
 9 
10 public:
11     virtual void say();
12 };
13 
14 class Line: public Sharp {
15 
16 public:
17     virtual void say();
18 };
19 
20 class Init {
21 
22 public:
23     void declation(const char* arg);
24 };
25 
26 void Point::say() {
27 
28     std::cout<<"Point\n"<<std::endl;
29 }
30 REGIST(Point)
31 
32 void Line::say() {
33 
34     std::cout<<"Line\n"<<std::endl;
35 }
36 REGIST(Line)
37 
38 void Init::declation(const char* arg) {
39 
40     std::cout<<"demo"<<std::endl;
41     std::cout<<"Argument: "<<arg<<std::endl;
42 }
43 REGIST(Init)

  配置文件

1 <Configure>
2     <Function name="declation" scale="Init">
3         <Argument>1</Argument>
4     </Function>
5 
6     <Bean name="Sharp" reference="Line" />
7 </Configure>

  程序

1 int main() {
2 
3     BeanFactory::sharedFactory().setContextEnv("context.xml");
4     BeanFactory::sharedFactory().configure("configure.xml");
5 
6     Sharp* s = static_cast<Sharp*>(BeanFactory::sharedFactory().getBeanByName("Sharp"));
7     s->say();
8 }

  運行結果:

 

  結果跟預期的一樣, 在下一篇中我將介紹我實現的方法


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM