所需工具:g++編譯器
前言:
本文主要探討並實現了如何用C++實現類似於.NET & JAVA的反射機制。
探討:
近由於項目需求,我們需要用C++編寫一個腳本執行程序(簡而言之,是編寫一個腳本執行框架)。但是很不幸的是,C++中並沒有一種想相關的機制來僅僅通過一串函數名的字符串來對應執行函數(反射機制)。
舉個實際的例子吧:
我現在有這麼一個類:
TestClassA{
void func0();
Void func1();
};
那麼我希望在我的mian函數中如果出現 「TestClassA::func0」這樣的字樣的話 ,我能夠通過某種方法真的執行這個函數(注意:不能再編寫代碼時寫死哦~)
其實,C++中也不是真的不支持反射,比如C++11的RTTI中的typeid就有那麼一點點萌芽~,但是很可以的是,RTTI的重點在於類型檢查,而不是執行具體方法。
廢話不多說了,開始正式思路探討吧。
思路:
我研究了一下JAVA的反射,他們是這樣用的
Foo foo = new Foo("這個一個Foo對象!");
Class clazz = foo.getClass();
Method m1 = clazz.getDeclaredMethod("outInfo");
Method m2 = clazz.getDeclaredMethod("setmsg", String.class);
Method m3 = clazz.getDeclaredMethod("getMsg");
m1.invoke(foo);
m2.invoke(foo, "重新設置msg信息!");
String msg = (String) m3.invoke(foo);
System.out.println(msg);
(引用地址:http://lavasoft.blog.51cto.com/62575/61002/)
那麼我覺得JAVA編譯器在編譯過程中肯定是對Foo類中的各種成員函數進行了序列化,並把它放到了一個容器中。當我們要反射時,便會從這個容器中去除對應函數的函數指針然後通過回調函數執行。
那麼我們的思路應該是:
0 定義一個函數指針,該函數指針應該與我們要反射的函數同類型。
1 創建以一個反射類,該類負責序列化自寫類中的方法,並將其放入一個map容器中
2 在main函數運行前,將我們可能被反射的函數進行註冊
代碼:
0 定義函數指針(當然我們的函數也要寫成這樣子的)
typedef void (TestClassA::*PTRDeclareFunc)(int,int);
1 定義反射類
注意:反射類應該是單例模式;應該有一個靜態方法來反射;應該有一個方法來註冊;
class ReflectAction{
private:
map<string,PTRDeclareFunc> m_classFuncMap;
ReflectAction(){}
public:
//=============================================
static ReflectAction& getFuncInstance();
void getClassFuncByName(string className,int a,int b)
{
map<string, PTRDeclareFunc>::const_iterator iter;
iter = m_classFuncMap.find(className) ;
if ( iter == m_classFuncMap.end() )
return;
else
{
TestClassA *q = new TestClassA;
PTRDeclareFunc p = iter->second;
(q->*p)(a,b);
}
return ;
}
//=============================================
void registClassFunc(string name, PTRDeclareFunc method)
{
m_classFuncMap.insert(pair<string, PTRDeclareFunc>(name, method)) ;
}
};
ReflectAction& ReflectAction::getFuncInstance(){ static ReflectAction sigleClass; return sigleClass;}
2 為我們書寫的類進行註冊
(我們用宏的方式來代替手動書寫,這樣比較節省書寫時間)
注意:__attribute((constructor))該關鍵字指該函數在main函數執行前運行
#define REGISTER(className,funcName) \
__attribute((constructor)) void before_main##className##funcName() \
{
ReflectAction::getFuncInstance().registClassFunc(#className#funcName,className::funcName); \
}
使用方法是:
REGISTER(TestClassA,m_func);
3 我們自己的類是:
class TestClassA{
public:
void m_func(int a,int b);
};
void TestClassA::m_func(int a,int b){
cout<<"hello TestClassA" << a << b <<endl;
};
4 main函數是:
int main(int argc,char* argv[]){
ReflectAction::getFuncInstance().getClassFuncByName("TestClassAm_func",1,1);
}
好的,代碼難度不大,以上代碼只是關鍵代碼。大家可以下載出源碼自行實驗:
https://github.com/Basic-Linux/FunnyZone/裡面有一個文件叫CPPReflect.cpp的文件。
執行效果:
嵌入式物聯網需要學的東西真的非常多,千萬不要學錯了路線和內容,導致工資要不上去!
分享大家一個資料包,差不多150多G。裡面學習內容、面經、項目都比較新也比較全!加微信領取資料