Chinaunix
标题:
C++ 如何反射调用方法
[打印本页]
作者:
buaaspy
时间:
2013-12-10 10:58
标题:
C++ 如何反射调用方法
Hi~最近想实现一个简单的C++反射应用,根据URI调用指定对象的指定方法,大致如下:
//@(path="/api/ubuntu")
DECLARE_DYN_CLASS(Test) {
public:
Test()
{ }
//@(path="/display", method="UPDATE")
void display()
{ std::cout << "Test::display()" << std::endl; }
};
//@(path="/api/lxc")
DECLARE_DYN_CLASS(Api) {
public:
Api()
{ }
//@(path="/create", method="POST")
void do_post()
{ std::cout << "Api::do_post()" << std::endl; }
//@(path="/create", method="GET")
void do_get()
{ std::cout << "Api::do_get()" << std::endl; }
};
int main()
{
Test* test = (Test*)ClassFactory::create_instance_for_name("Test");
test->display();
Api* api = (Api*)ClassFactory::create_instance_for_name("Api");
api->do_post();
api->do_get();
return 0;
}
复制代码
问题是不知道如何反射调用类的成员函数,目前想到的方法是:
typedef void (ClassType::*PMF)(std::string request);
然后将成员函数指针强制转换为int*存到一个map里,可是会出现
链接错误,折腾了好几天了,哪位高手给指点迷津下~多谢了^^
Demo.rar
(55.68 KB, 下载次数: 4)
2013-12-10 10:57 上传
点击文件名下载附件
作者:
truekbcl
时间:
2013-12-11 10:09
Test* test = (Test*)ClassFactory::create_instance_for_name("Test");
test->display();
----------
这样的语法,表明Test与是否反射没有关系。反射应该是
Foo * f = create_instance("test");
f->invoke("display");
作者:
ljpdxj
时间:
2013-12-11 10:21
本帖最后由 ljpdxj 于 2013-12-11 10:22 编辑
楼上太高深了!
作者:
sxcong
时间:
2013-12-11 10:47
其实COM也算是反射吧,所有的函数都在IDL里写着。换成spring,只不过改成 xml了。不过spring可以赋值,这东西和程序读配置文件有多大区别呢
作者:
buaaspy
时间:
2013-12-11 11:22
回复
2#
truekbcl
确实如此,
目前我能做到的:
1)类对应的URI 映射到 类名;方法对应的URI和METHOD 映射到 方法名
2)类名 映射到 创建实例的方法指针;方法名 映射到 成员函数指针
接下来如何组装不知道了。。。其实不一定要达到真正的反射,只是想用C++简单模拟Spring根据注解装配对象和引导请求的过程,
还希望能给点进一步的建议,感激不尽
作者:
zhujiang73
时间:
2013-12-11 12:09
回复
1#
buaaspy
这事还是改编译器比较好。
作者:
群雄逐鹿中原
时间:
2013-12-11 12:33
高端!大气!上档次!
作者:
yao050421103
时间:
2013-12-11 12:44
这个问题的难点在于可变参数的封装,因为成员函数的参数是不确定的。
使用map的方式,只能针对特定签名形式的成员函数进行封装,而无法提供统一的接口。
可以考虑使用代码生成技术,使用python之类的脚本语言读入定义的C++文件,将class解析出来,然后针对各个成员函数生成Invoke方法。
buaaspy 发表于 2013-12-11 11:22
回复 2# truekbcl
确实如此,
作者:
windoze
时间:
2013-12-11 13:52
本帖最后由 windoze 于 2013-12-11 13:57 编辑
其实吧,你为什么一定要把这些东西塞到一个class里呢?
为什么不干脆写成这样:
typedef std::map<std::pair<std::string, std::string>, std::function<void()>> action_map;
action_map the_map({
{
{"GET", "/some/path"},
[](){ std::cout << "GET /some/path" << std::endl; }
},
{
{"POST", "/some/path"},
[](){ std::cout << "POST /some/path" << std::endl; }
},
{
{"GET", "/some/other/path"},
[](){ std::cout << "GET /some/other/path" << std::endl; }
},
});
复制代码
使用的时候你可以这样:
action_map::const_iterator i=the_map.find({method, path});
if(i==the_map.end()) {
// Send 404 response
} else {
i->second();
}
复制代码
作者:
buaaspy
时间:
2013-12-11 18:09
回复
8#
yao050421103
好主意!
作者:
buaaspy
时间:
2013-12-11 18:10
回复
9#
windoze
好主意!
作者:
truekbcl
时间:
2013-12-11 19:43
buaaspy 发表于 2013-12-11 11:22
回复 2# truekbcl
确实如此,
想做到其他语言那样的反射,只可能在编译器做手脚,否则只能做到局部反射。最简单的大致如下:
1、定义一个method类,放置所有需要调用的函数类型
class method
{
string _method_name;
method * _next;
const string & method_name() { return _method_name(); }
virtual void invoke();
virtual void invoke(int );
};
这表明,反射需要用到 obj->xxx(), obj->xxx(int)这两个类型的函数。
2、然后定义Class,
class Class
{
method*> _methods;
method * get_method(const string & methodName);
};
3、在类中使用:
class A
{
void test0(){ cout << "test"<<endl; }
void test1(int x) { cout << "text " << x << endl; }
// 以下2段代码,用宏生成,并且把method
class method_A_test_0 : public method
{
method_A_test_0(const string & func):_method_name(func){}
virtual void invoke() {test0(); }
};
class method_A_test_1 : public method
{
method_A_test_1(const string & func):_method_name(func){}
virtual void invoke(int x) {test1(x); }
};
};
4、
把A类中的method派生类放入到一个Class中,用静态变量Class即可。
比如在定义派生类时,生成链表,并放入到Class静态变量。
5、定义类工厂
class ClassFactory
{
void register(const string & className);
Class * get(const string & cn);
};
6、使用:
Class * p = ClassFactory.get("A");
p->get_method("test0").invoke();
p->get_method("test1").invoke(2);
改进:可以用模板与循环宏生成更多类型的参数,但是参数仍然只能是原始类型。但是也麻烦很多,我觉得意义不大。
另外,把method这个基类用宏来定义,如果在不同地方使用,修改也简单,其他代码都不变。
不建议使用反射,显然要慢很多。
作者:
lost_templar
时间:
2013-12-12 01:04
本帖最后由 lost_templar 于 2013-12-12 01:10 编辑
组合使用 sfinae 与 enable_if,我实现了一个简单的,纯人肉的……
#include <type_traits>
#include <iostream>
#define DETECT_METHOD(method) \
template<typename T, typename Sign> \
struct class_has_method_##method \
{ \
template <typename U, U> struct type_check; \
template <typename V> static char &chk(type_check<Sign, &V::method> *); \
template <typename > static long &chk(...); \
static bool const value = sizeof(chk<T>(0)) == sizeof(char); \
}
struct Test
{
void display()
{
std::cout << "Test::display() called.\n";
}
};
struct Api
{
void do_post()
{
std::cout << "Api::do_post() called.\n";
}
void do_get()
{
std::cout << "Api::do_get() called.\n";
}
};
DETECT_METHOD( display );
template<typename T>
typename std::enable_if<class_has_method_display<T, void( T::* )()>::value>::type display( T* pt )
{
( *pt ).display();
}
template<typename T>
typename std::enable_if < !class_has_method_display<T, void( T::* )()>::value >::type display( T* pt )
{
std::cerr << "No Method display defined for this struct.\n";
}
DETECT_METHOD( do_get );
template<typename T>
typename std::enable_if<class_has_method_do_get<T, void( T::* )()>::value>::type do_get( T* pt )
{
( *pt ).do_get();
}
template<typename T>
typename std::enable_if < !class_has_method_do_get<T, void( T::* )()>::value >::type do_get( T* pt )
{
std::cerr << "No Method do_get defined for this struct.\n";
}
DETECT_METHOD( do_post );
template<typename T>
typename std::enable_if<class_has_method_do_post<T, void( T::* )()>::value>::type do_post( T* pt )
{
( *pt ).do_post();
}
template<typename T>
typename std::enable_if < !class_has_method_do_post<T, void( T::* )()>::value >::type do_post( T* pt )
{
std::cerr << "No Method do_post defined for this struct.\n";
}
int main()
{
/*
Test* test = (Test*)ClassFactory::create_instance_for_name("Test");
test->display();
Api* api = (Api*)ClassFactory::create_instance_for_name("Api");
api->do_post();
api->do_get();
*/
Test* test = new Test {};
display( test );
do_post( test );
do_get( test );
delete test;
Api* api = new Api {};
display( api );
do_post( api );
do_get( api );
delete api;
return 0;
}
复制代码
输出是:
Test::display() called.
No Method do_post defined for this struct.
No Method do_get defined for this struct.
No Method display defined for this struct.
Api::do_post() called.
Api::do_get() called.
复制代码
只是不知是否合乎楼主需求。
欢迎光临 Chinaunix (http://bbs.chinaunix.net/)
Powered by Discuz! X3.2