Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3228025
  • 博文数量: 346
  • 博客积分: 10189
  • 博客等级: 上将
  • 技术积分: 3125
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-05 19:46
文章分类

全部博文(346)

文章存档

2013年(35)

2011年(35)

2010年(76)

2009年(48)

2008年(152)

分类: C/C++

2010-03-27 13:40:57

我最近在实现一个事件处理器,应用到了一种“通用成员函数指针的注册”,先声明,这个名词是我给起的,不过我觉得并不充分恰当,但也想不出什么更好的词,看完下面的介绍,也考考您,看这玩意叫个啥比较合适。

先说需求:这个事件处理器需要在捕获一个事件后,调用已注册的处理函数。看起来很普通,呵呵,不过,这个事件处理函数不一定是哪个类的成员函数(但肯定是成员函数),函数的形式是一定的,即拥有相同的返回类型和参数列表。而这些事件和处理函数,注册在一个全局的结构体中。

问题的提出:同一个结构体的各字段类型是固定的,所以仔细想一下,这个保存着事件和处理函数的结构体应该怎么定义呢?事件的类型是一定的,但是处理函数呢?需求中明确指出,这个处理函数很有可能是不同类中的成员函数,而成员函数指针在定义时,是需要明确类的,比如:
void (MyClass::*func_ptr)(void);

定义了一个指向MyClass类中的无参数、返回类型为void的成员函数指针。这样看来,我没有办法定义一个适用于任何类成员函数的指针呀?

那么,我能不能定义一个基类 HandlerBase,让所有包含事件处理函数的类都继承自HandlerBase呢?这样我可以在定义结构体时,将事件处理函数指针定义为
void (HandlerBase::*func_ptr)(void);
刚刚有这个想法时,我还禁不住一阵欣喜,但细想才发现,这也是行不通的,因为这样的话,我们必需将所有子类中用到的事件处理函数在HandlerBase中声明为虚函数,这样一来,代码就显得混乱没有章法了,所以,这个方法还是 pass 了吧。

看上去问题可能真的很复杂,那怎么办泥?仔细研究后,感觉只有用模板来解决问题了,具体怎么来设计呢?

(补充:当我写完下面一段话再回读的时候,发现我的表达可能并不是太好懂,那么请您硬着头皮看到最后,我相信您一定能明白我的意思的)

首先,通过上面的分析,看来直接将事件处理函数注册到结构体中是不行的,因为同一个结构体,不可能包含一种以上类型的成员。那么,就让我们把这些类型的成员做个统一处理:让我们声明一个基类(FuncCaller),然后把不同的处理函数注册到它的子类(FuncItem)中去,再通过基类中提供的方法来间接调用处理函数!

不过,我可不想针对每一个可能出现事件处理函数的类,都声明一个对应的 FuncItem(因为他们包含的成员函数指针类型不同),那好,现在到了模板上场的时候了,上代码:
class FuncCaller
{
//

};

template 
<typename T>
class FuncItem : public FuncCaller
{
//

};

有了这样的定义,我就可以在FuncItem中添加一个指针类型,并定义一个成员变量:

typedef void (T::*HandlerPtr)(void* param);
HandlerPtr handler;


param是事件到达时,可能传递给处理函数的数据。现在,我们在基类FuncCaller中,定义一个函数,来间接调用事件处理函数:

virtual void func_call(void* obj_ptr, void* param)=0;


之所以为纯虚函数,是因为基类是没有实现它的意义的。另外,形参 obj_ptr 用来传递调用事件处理函数的对象,因为成员函数指针是需要通过类的实例来调用的。
下面来看看FuncItem类对 func_call 的实现:

void func_call(void* obj_ptr, void* param)
{
    
if!obj_ptr )
        
return ;

    (((T
*)obj_ptr)->*handler)(param);
}


差不多了,来看看现在这两个类长成什么样了:

 1class FuncCaller
 2{
 3public:
 4    virtual void func_call(void* obj_ptr, void* param)=0;
 5
 6}
;
 7
 8template <typename T>
 9class FuncItem : public FuncCaller
10{
11private:
12    typedef void (T::*HandlerPtr)(void* param);
13    HandlerPtr handler;
14
15public:
16    void func_call(void* obj_ptr, void* param)
17    {
18        if!obj_ptr )
19            return ;
20
21        (((T*)obj_ptr)->*handler)(param);
22    }

23
24}
;

嗯,还不错,基本的形式已经有了,不想写太长,待下一篇,再来看看具体事件处理结构的设计

阅读(3627) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-06-04 15:39:20

你好,你的结论很精彩。 但是我想问下你有办法把一个void指针转化为一个通用成员函数指针吗?

chinaunix网友2010-06-04 15:38:53

你好,你的结论很精彩。 但是我想问下你有办法把一个void指针转化为一个通用成员函数指针