所需工具: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 定义反射类

注意:反射类应该是单例模式;应该有一个静态方法来反射;应该有一个方法来注册;

  1. class ReflectAction{
  2. private:
  3. map<string,PTRDeclareFunc> m_classFuncMap;
  4. ReflectAction(){}
  5. public:
  6. //=============================================
  7. static ReflectAction& getFuncInstance();

  8. void getClassFuncByName(string className,int a,int b)
  9. {
  10. map<string, PTRDeclareFunc>::const_iterator iter;
  11. iter = m_classFuncMap.find(className) ;
  12. if ( iter == m_classFuncMap.end() )
  13. return;
  14. else
  15. {
  16. TestClassA *q = new TestClassA;
  17. PTRDeclareFunc p = iter->second;
  18. (q->*p)(a,b);
  19. }
  20. return ;
  21. }
  22. //=============================================
  23. void registClassFunc(string name, PTRDeclareFunc method)
  24. {
  25. m_classFuncMap.insert(pair<string, PTRDeclareFunc>(name, method)) ;
  26. }
  27. };
  28. ReflectAction& ReflectAction::getFuncInstance(){ static ReflectAction sigleClass; return sigleClass;}
  29. 2 为我们书写的类进行注册
  30. (我们用宏的方式来代替手动书写,这样比较节省书写时间)
  31. 注意:__attribute((constructor))该关键字指该函数在main函数执行前运行
  32. #define REGISTER(className,funcName) \
  33. __attribute((constructor)) void before_main##className##funcName() \
  34. {
  35. ReflectAction::getFuncInstance().registClassFunc(#className#funcName,className::funcName); \
  36. }
  37. 使用方法是:
  38. REGISTER(TestClassA,m_func);
  39. 3 我们自己的类是:
  40. class TestClassA{
  41. public:void m_func(int a,int b);
  42. };
  43. void TestClassA::m_func(int a,int b){
  44. cout<<"hello TestClassA" << a << b <<endl;
  45. };
  46. 4 main函数是:
  47. int main(int argc,char* argv[]){
  48. ReflectAction::getFuncInstance().getClassFuncByName("TestClassAm_func",1,1);
  49. }

好的,代码难度不大,以上代码只是关键代码。大家可以下载出源码自行实验:

https://github.com/Basic-Linux/FunnyZone/里面有一个文件叫CPPReflect.cpp的文件。

执行效果:

forum.jpg