C++ Reflection 的簡單實現 (反射)
阿新 • • 發佈:2019-02-19
之前被一些指令碼語言慣懷了,重新寫C++程式碼居然有點不適應。最明顯的是C++沒有語言層面的反射機制。回想QT是有反射的,但人家是牛X到自己實現了一個moc層,從根本上解決了這個問題。而我只是想實現一個輕量化的解決方案,最好能馬上上手用,最好是類似修飾類一樣的東西,可以和現有程式碼相容。網上搜了下,發現沒有一個我喜歡的方案。但是受他們的啟發,自己實現了一個。
思路是這樣滴,我想要這樣敲程式碼ReflectionClass *ptr = ObjectFactory::createObject("ReflectionClass"); ObjectFactory怎麼知道如何建立ReflectionClass呢?自然是需要給ObjectFactory一個註冊函式,我可以定義一個全域性的hash容器,來裝每個類對應的建立函式。每個類在定義好之後,自己把自己的建立函式註冊進去。這樣就萬事大吉啦。
進一步想到,一般需要在main函式執行之前,把所有類註冊完畢。我定義一個小的註冊類模板,在它的建構函式裡進行註冊,每個類定義好之後,再定義一個相應的全域性變數,這樣註冊函式就能先於main函式運行了。
最後,把這些過程寫成巨集,呼叫的時候就能一句話完成上述全部的工作。
說的太複雜了,還是直接看程式碼簡單一些。
思路是這樣滴,我想要這樣敲程式碼ReflectionClass *ptr = ObjectFactory::createObject("ReflectionClass"); ObjectFactory怎麼知道如何建立ReflectionClass呢?自然是需要給ObjectFactory一個註冊函式,我可以定義一個全域性的hash容器,來裝每個類對應的建立函式。每個類在定義好之後,自己把自己的建立函式註冊進去。這樣就萬事大吉啦。
進一步想到,一般需要在main函式執行之前,把所有類註冊完畢。我定義一個小的註冊類模板,在它的建構函式裡進行註冊,每個類定義好之後,再定義一個相應的全域性變數,這樣註冊函式就能先於main函式運行了。
最後,把這些過程寫成巨集,呼叫的時候就能一句話完成上述全部的工作。
說的太複雜了,還是直接看程式碼簡單一些。
使用 REG_REFLECTION_CLASS註冊需要反射的類#ifndef _REFLECTION_ #define _REFLECTION_ // this file realize a simple reflection mechanism // usage : // 1 use the macro to Register the class REG_REFLECTION_CLASS(ClassName). // 2 then you can create the instance like that // ClassName *instance = (ClassName*) ObjectFactory::createObject("ClassName"); // example : // REG_REFLECTION_CLASS(int); // int *i = (int*) ObjectFactory::createObject("int"); #include <stdlib.h> #include <tr1/unordered_map> typedef void* (*FactoryCreate_PTR) (); std::tr1::unordered_map<std::string,FactoryCreate_PTR> g_creator_map; template <class T> class RegisterReflectionClass { public: RegisterReflectionClass (std::string name,FactoryCreate_PTR ptr) { std::tr1::unordered_map<std::string,FactoryCreate_PTR>::const_iterator it = g_creator_map.find(name); if(it == g_creator_map.end()){ g_creator_map[name] = ptr; }else{ std::cout << "exit error : Class \"" << name << "\" has been registered before" << std::endl; exit (EXIT_FAILURE); } } }; class ObjectFactory{ public: static void* createObject(std::string name) { void* obj; std::tr1::unordered_map<std::string,FactoryCreate_PTR>::const_iterator it = g_creator_map.find(name); if(it != g_creator_map.end()){ obj = (it->second)(); return obj; } } }; #define REFLECTION_CLASS_CREATOR(class_name) \ void* class_name##_creator() \ { \ class_name *tmp = new class_name(); \ return (void*)tmp; \ } \ #define REG_REFLECTION_CLASS(class_name) \ REFLECTION_CLASS_CREATOR(class_name) \ RegisterReflectionClass<class_name> Reg##class_name(#class_name,class_name##_creator); \ #endif
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">sample程式碼:</span>
#include <iostream> #include <string> #include "reflection.hpp" using namespace std; class TestClass { public: TestClass(string s1="",string s2="", string s3="") { p1 = s1; p2 = s2; p3 = s3; } void init(string s1="",string s2="", string s3="") { p1 = s1; p2 = s2; p3 = s3; } void print() { cout << p1 << " " << endl; cout << p2 << " " << endl; cout << p3 << " " << endl; } private: string p1,p2,p3; }; REG_REFLECTION_CLASS(TestClass); REG_REFLECTION_CLASS(int); int main() { int *i = (int*) ObjectFactory::createObject("int"); cout << *i << endl; TestClass *test = (TestClass*) ObjectFactory::createObject("TestClass"); test->init("str1","str2","str3"); test->print(); return 0; }