1.反射函数的调用接口(getMethodField)
#define DECLARE_REFLECT_METHOD(CLASS, ...) \
DEFINE_METHOD_MAP \
sp<_MethodField> getMethodField(std::string name) \
{ \
auto method = __reflect_methods__[name]; \
return MethodField::New(method, this); \
} \
IMPLE_REFLECT_FUNCTION_DETECT(CLASS, GET_ARG_COUNT(__VA_ARGS__), __VA_ARGS__)
getMethodField和java的反射方法类似,就是根据函数名字来从map表里面找到这个函数。
2.__reflect_methods__表结构:
//反射函数表
#define DEFINE_METHOD_MAP std::map<std::string,void *> __reflect_methods__;
//对象构造时,将反射函数类放入表中
#define DEFINE_GENERAL_ADD_METHOD(CLASS, METHOD) \
template <typename ClassType, typename ReturnType, typename... Args> \
void __add_method_##METHOD(ReturnType (ClassType::*)(Args...), std::string name) \
{ \
__reflect_methods__[name] = (void *)(new reflect_##METHOD<Args...>(this)); \
}
//每个函数对应一个反射函数类
#define DEFINE_GENERAL_ADD_METHOD(CLASS, METHOD) \
template <typename ClassType, typename ReturnType, typename... Args> \
void __add_method_##METHOD(ReturnType (ClassType::*)(Args...), std::string name) \
{ \
__reflect_methods__[name] = (void *)(new reflect_##METHOD<Args...>(this)); \
}
因为函数的入参和各种各样,无法定义一个统一的模板父类,所以这里粗暴的用void*来存储,使用的时候再强制转换会对应的反射函数类。
3.反射函数类基类
template<typename ...Args>
class __reflect_base__:public _Object {
public:
virtual MethodResult call() = 0;
template<typename ...Args2>
MethodResult execution(Args2... args) {
params = std::make_tuple(args...);
return call();
}
protected:
std::tuple<Args...> params;
};
所有的反射函数都会自动生成一个基于__reflect_base__的反射函数类(最后存放在__reflect_methods__中),这个基类主要对外提供一个execution的函数(类似java反射的invoke),将可变参数转换成tuple,传递给子类(具体的反射函数类)。
4.反射函数类实现
template <typename... Args> \
class reflect_##METHOD : public __reflect_base__<Args...> \
{ \
public: \
reflect_##METHOD(_##CLASS *p) : pthis(p) \
{ \
} \
MethodResult call() \
{ \
auto f = [&](auto &&...args) { \
return pthis->METHOD(args...); \
}; \
if constexpr (!__is_void_function__(&_##CLASS::METHOD)) \
{ \
return MethodResult::New(std::apply(f, __reflect_base__<Args...>::params)); \
} \
if constexpr (__is_void_function__(&_##CLASS::METHOD)) \
{ \
std::apply(f, __reflect_base__<Args...>::params); \
return nullptr; \
} \
} \
\
private: \
_##CLASS *pthis; \
};
这里主要关键点时要区分处函数是void还是非void,void函数不需要返回值,所以我们通过向上返回null来表示。其他函数的返回值存放在MethodResult的std::any类型中。确定是否是void函数使用了模板方法:
template <typename ClassType,typename ReturnType,typename... Args>
constexpr bool __is_void_function__(ReturnType (ClassType::*)(Args...)) {
return false;
}
template <typename ClassType,typename... Args>
constexpr bool __is_void_function__(void (ClassType::*)(Args...)) {
return true;
}
此外,如果是指用if判断,编译时是不会做判断的,导致可能出现函数类型不匹配等问题(模板会将同一种情况在if和非if的分支里都编译,结果就出错了),这里用了C++17的一个新语法特性(if constexpr),要求编译时就进行计算。
5.释放
由于我们__reflect_methods__里面存放的数据在析构的时候需要释放。但是由于__reflect_methods__里面我们存放的是void*数据,所以不能直接delete,需要转化为原来的类,所以我们为每个反射函数定义了一个释放类,这个释放类实际上是通过传入的函数类型来转化会需要释放分指针:
#define DEFINE_METHOD_CLASS(CLASS, METHOD) \
template <typename ClassType, typename ReturnType, typename... Args> \
void __delete_method_##METHOD(ReturnType (ClassType::*)(Args...)) \
{ \
void *p = __reflect_methods__[#METHOD]; \
reflect_##METHOD<Args...> *v = (reflect_##METHOD<Args...> *)p; \
delete v; \
} \
使用如下:
void __release_reflect_method__() \
{ \
__delete_method_##M1(&_##CLASS::M1); \
} \
下面是一个函数反射使用的例子,个人觉得还可以吧。哈哈哈哈。
#include <stdio.h>
#include "Object.hpp"
#include "String.hpp"
#include "ReflectMethod.hpp"
#include "TestLog.hpp"
#include <any>
using namespace obotcha;
DECLARE_CLASS(testReflect_1) {
public:
int test1() {
return 1;
}
int test2(int v) {
return v + 1;
}
int test3(int v,int j) {
return v + j;
}
int test4(int v,int j,int k) {
return v + j + k;
}
void test5(int v,int j,int *p) {
*p = v + j;
}
DECLARE_REFLECT_METHOD(testReflect_1,test1,test2,test3,test4,test5)
};
void testReflect_Int_int_int() {
Object t = (Object)testReflect_1::New();
auto method = t->getMethodField("test1");
auto result = method->execute();
if(result->get<int>() != 1) {
TEST_FAIL("testReflect_Int_int_int case1");
}
auto method2 = t->getMethodField("test2");
auto result2 = method2->execute(100);
if(result2->get<int>() != 101) {
TEST_FAIL("testReflect_Int_int_int case2");
}
auto method3 = t->getMethodField("test3");
auto result3 = method3->execute(1,2);
if(result3->get<int>() != 3) {
TEST_FAIL("testReflect_Int_int_int case3");
}
auto method4 = t->getMethodField("test4");
auto result4 = method4->execute(1,2,3);
if(result4->get<int>() != 6) {
TEST_FAIL("testReflect_Int_int_int case4");
}
auto method5 = t->getMethodField("test5");
int k = -1;
method5->execute(1,2,&k);
if(k != 3) {
TEST_FAIL("testReflect_Int_int_int case5");
}
TEST_OK("testReflect_Int_int_int case100");
}
所以总结下来,整个反射实现的流程如下
1.生成流程:
DECLARE_REFLECT_METHOD(Class,Method1)->生成Method1的反射类->初始化时存入__reflect_methods__表中。
2.调用流程:
从__reflect_methods__表中找到对应的类->将可变参数转换成tuple->触发execute
Obotcha对应项目:
GitHub - wangsun1983/Obotcha: Tool library writen by C++17
相关实现:
Obotcha/lang/include/ReflectMethod.hpp at master · wangsun1983/Obotcha · GitHub