在陈硕的github中看到一段非常有意思的代码,可以实现根据消息类型分发到不同的回调函数(link)。代码里是用的Protobuf的反射,本文使用支持多基类的C++类反射实现文中的的反射来改写一下。
首先来定义接口,如果是下面的用例,使用一个类名为key,callback函数为value的hash表就很容易的实现了:
class
Foo :
public
Object {};
void
OnRecvFoo(Object
*
foo); dispatcher.Register(
"
Foo
"
, OnRecvFoo);
但是这样在OnRecvFoo中需要做类型转换,调用Register时也需要手动输入类名字符串,容易出错且麻烦,所以有了如下用例:
void
OnRecvFoo(Foo
*
foo); dispatcher.Register
<
Foo
>
(OnRecvFoo);
下面来分析一下实现,首先定义接口:
class
ObjectDispatcher {
public
: template
<
typename T
>
void
Register(
const
CallbackFunc
<
T
>&
func);
void
OnReceive(Object
*
obj)
const
; };
Register使用带有模板参数的回调函数作为参数,底层消息系统调用OnReceive来分发消息。为了实现注册分发,需要建立一个hash表,key是消息的类型信息,value是带有模板参数的回调函数。由于value类型并不一致,为了放到hash表中,需要定义一个共同基类:
class
ReceiveCallback {
public
:
virtual
~
ReceiveCallback() {};
virtual
void
OnReceive(Object
*
obj)
=
0
; };
然后定义一个带模板参数的派生类表示回调函数:
template
<
typename T
>
class
ReceiveCallbackT :
public
ReceiveCallback {
public
: typedef boost::function
<
void
(T
*
)
>
ObjectCallbackFunc; ReceiveCallbackT(
const
ObjectCallbackFunc
&
func) : m_func(func) { }
virtual
void
OnReceive(Object
*
obj) { T
*
obj1
=
dynamic_cast
<
T
*>
(obj); assert(obj1
!=
NULL); m_func(obj1); }
protected
: ObjectCallbackFunc m_func; };
在Dispatcher中添加一个hash表存储对应关系,并定义一个默认回调函数用于处理没有注册的消息:
class
ObjectDispatcher {
public
: ObjectDispatcher() : m_default_callback(boost::bind(
&
ObjectDispatcher::DefaultObjectCallback,
this
, _1)) { } template
<
typename T
>
void
Register(
const
typename ReceiveCallbackT
<
T
>
::ObjectCallbackFunc
&
func) {
if
(m_callbacks.count(
&
T::ms_classInfo)
!=
0
) wximpl::LOG_INFO(
"
ObjectDispatcher.Connect twice: %s.
"
, T::ms_classInfo.GetClassName().c_str()); boost::shared_ptr
<
ReceiveCallbackT
<
T
>
>
pc(
new
ReceiveCallbackT
<
T
>
(func)); m_callbacks[
&
T::ms_classInfo]
=
pc; }
void
OnReceive(Object
*
obj)
const
{ CallbackMap::const_iterator itor
=
m_callbacks.find(obj
->
GetClassInfo());
if
(itor
!=
m_callbacks.end()) { itor
->
second
->
OnReceive(obj); }
else
{ m_default_callback(obj); } }
void
DefaultObjectCallback(Object
*
obj) { wximpl::LOG_INFO(
"
UnProcessed object :%s.
"
, obj
->
GetClassInfo()
->
GetClassName().c_str()); }
private
: typedef std::map
<
const
reflection::ClassInfo
<
Object
>*
, boost::shared_ptr
<
ReceiveCallback
>
>
CallbackMap; CallbackMap m_callbacks; boost::function
<
void
(Object
*
)
>
m_default_callback; };
这样的消息分发机制在一些通信系统中非常实用。