C++中建立对象间消息连接的一种系统方法

成员函数RemoveCallback用来删除注册在事件对象上的回调函数。它的三个重载版本依次为:

void CallBack::RemoveCallBack(char *event,CallBackFunction cbf,CallBack *p);
void CallBack::RemoveCallBack(char *event,CallBackStaticFunction cbsf);
void CallBack::RemoveCallBack(char *event);

其中,event,cbf,cbsf,p等参数和成员函数AddCallBack中各参数一样。第一个RemoveCallBack用于删除注册在事件event上某回调对象的一个成员函数。第二个RemoveCallBack用于删除注册在事件event上的某普通函数或某回调类的一个静态成员函数。第三个RemoveCallBack用于删除注册在事件event上的全部回调函数。

二、CallBack类的使用方法

使用CallBack类,可按以下步骤进行:

1.确定程序中哪些对象间存在关系,需要建立消息连接。并确定在各特定消息连接关系中,哪个对象是事件对象,哪个对象是回调对象。

2.事件对象类和回调对象类都必须从CallBack类继承,以获得回调支持。

3.为事件对象注册回调数据。包括:事件名,回调函数名,指向回调对象的指针。

4.当你感兴趣的事件发生时,在事件对象类引发事件的成员函数中调用CallCallBack函数。

下面是一个具体的例子。通过它你会对Callback类的使用方法有进一步的了解。

//测试程序文件:test.cpp 
#include"callback.h"
//“扬声器”类 
class Speaker:public CallBack
{
    private:
        int volume;
    public:
        Speaker(int v): volume(v) {}
               void IncreaseVolume(int v) //增加音量成员函数
        {
            volume += v;
            if(volume > 20){ //“音量大于20”事件发生了
//调用注册在两事件上的回调函数
                CallCallBack("音量改变了");
                CallCallBack("音量大于20", &volume);
            }
        }
        void DecreaseVolume(int v) //降低音量成员函数
        {
            volume -= v;
            if(volume < 5){ //“音量小于5”事件发生了
//调用注册在两事件上的回调函数
CallCallBack("音量改变了");
                CallCallBack("音量小于5", &volume);
            }
        }
};
  //“耳朵”类 
class Ear : public CallBack
{
public: 
      static void Response(CallData callData) //对“音量改变”的反应
      {
          cout<<"音量改变了."<<endl;
      }
      void HighVoiceResponse(CallData callData)//对高音的反应
      {
          cout<<”喂!太吵了!现在音量是:"<<*((int *)callData)<<endl;
      }
      void LowVoiceResponse(CallData callData)// 对低音的反应
      {
          cout<<"啊!我听不清了。现在音量是:"<<*((int *)callData)<<endl;
      }
};
void main(void) 
{
      Speaker s(10); //现在音量为10
      Ear e;
    //为事件对象s注册回调函数
      s.AddCallBack("音量大于20”,(CallBackFunction)&Ear::HighVoiceResponse,&e);
      s.AddCallBack("音量小于5”,(CallBackFunction)&Ear::LowVoiceResponse,&e);
      s.AddCallBack("音量改变了",(CallBackStaticFunction)&Ear::Response);
   s.IncreaseVolume(12);//将音量增加12,现在音量位22
      s.DecreaseVolume(20);//将音量减少20,现在音量位2
}  

运行结果:

音量改变了.

喂!太吵了!现在音量是:22

音量改变了.

啊!我听不清了。现在音量是:2

在上例中,扬声器对象s为事件对象,耳朵对象e为回调对象。。s上被注册了三个事件:“音量改变了”,“音量大于20”,“音量小于5”。 回调函数分别为:Ear::Response, Ear::HighVoiceResponse,Ear::LowVoiceResponse。当扬声器s通过其成员函数IncreaseVolume和 DecreaseVolume改变音量时,回调对象e会自动作出反应。可见,通过使用CallBack类,在对象间建立消息连接已变为一项很简单和优美的工作。

附:完整程序(感兴趣的可以试一下)

//回调类的类结构:callback.h
#ifndef _CALLBACK_H
#define _CALLBACK_H
#include<stdlib.h>
#include<string.h>
#include<iostream.h>
#define CALLBACKLIST_INIT_SIZE 10
#define CALLBACKLIST_INCREMENT 5
class CallBack;
typedef void *CallData;//回调数据指针类型定义
typedef void (CallBack::*CallBackFunction)(CallData); //指向回调成员函数的指针
typedef void (*CallBackStaticFunction)(CallData); //指向静态成员函数或普通函数的指针类型定义
  class EventRecord{ 
    private:
        char *eventName;       //回调事件名称
        CallBack *pointerToCBO;//指向回调对象的指针
        //指向成员函数的指针和指向静态成员函数(或普通函数)指针的共用体
        union{
            CallBackFunction pointerToCBF;
CallBackStaticFunction pointerToCBSF;
        };
      public:
        EventRecord(void); //事件记录类的缺省构造函数
//构造包含成员函数的事件记录
EventRecord(char *ename,CallBack *pCBO,CallBackFunction pCBF);
//构造包含静态成员函数或普通函数的事件记录
EventRecord(char *ename,CallBackStaticFunction pCBSF);
          ~EventRecord(void);//析构事件记录
        void operator = (const EventRecord& er);//重载赋值运算符
        //判断当前事件记录的事件名是否为ename
 int operator == (char *ename) const;
        //判断当前事件记录是否和指定事件记录相等
int operator == (const EventRecord& er) const;
       void Flush(void);       //将当前事件记录清空
        int IsEmpty(void) const;//判断事件记录是否为空(即事件名是否为空)
          friend class CallBack;  //让CallBack类能访问EventRecord的私有成员;
};
  class CallBack { 
    private:
        EventRecord *callBackList; //回调事件表
        int curpos;                //当前事件记录位置
        int lastpos;               //回调表中最后一空闲位置
        int size;                  //回调表的大小
          void MoveFirst(void) { curpos = 0; }//将当前记录置为第一条记录
        void MoveNext(void) //将下一条记录置为当前记录
{
            if(curpos == lastpos) return;
            curpos++;
}
        //判断回调表是否被遍历完   
int EndOfList(void) const { return curpos == lastpos; }
    public:
        CallBack(void);//构造函数
        CallBack(const CallBack& cb);//拷贝构造函数
        ~CallBack(void);//析构函数
        void operator = (const CallBack& cb);// 重载赋值运算符
       //将回调对象的成员函数、静态成员函数(或普通函数)
//注册为事件对象的回调函数
  void AddCallBack(char *event,CallBackFunction cbf,CallBack *p);
        void AddCallBack(char *event,CallBackStaticFunction cbsf);
          //删除注册在指定事件上的回调函数
        void RemoveCallBack(char *event,CallBackFunction cbf,CallBack *p);
        void RemoveCallBack(char *event,CallBackStaticFunction cbsf);
        void RemoveCallBack(char *event);// 删除某事件的全部记录
          //执行注册在某一事件上的所有回调函数
        void CallCallBack(char *event, CallData calldata = NULL);
};
#endif

//回调类的实现:callback.cpp 
#include"callback.h"
//EventRecord类的实现
EventRecord::EventRecord(void)
{
    eventName = NULL;
    pointerToCBO = NULL;
    //因为sizeof(CallBackFunction) > sizeof(CallBackStaticFunction)
    pointerToCBF = NULL;
}
EventRecord::EventRecord(char *ename, CallBack *pCBO, CallBackFunction pCBF)
                 :pointerToCBO(pCBO), pointerToCBF(pCBF)
{
    eventName = strdup(ename);
}
EventRecord::EventRecord(char *ename, CallBackStaticFunction pCBSF)
  :pointerToCBO(NULL), pointerToCBSF(pCBSF)
{
    eventName = strdup(ename);
}
  EventRecord::~EventRecord(void) 
{
    if(eventName) delete eventName;
}
  void EventRecord::operator = (const EventRecord& er) 
{
    if(er.eventName)
        eventName = strdup(er.eventName);
    else
        eventName = NULL;
    pointerToCBO = er.pointerToCBO;
    pointerToCBF = er.pointerToCBF;
}
  int EventRecord::operator == (char *ename) const 
{
    if((eventName == NULL)||ename == NULL)
        return eventName == ename;
    else
        return strcmp(eventName,ename) == 0;
}
int EventRecord::operator == (const EventRecord& er) const
{
    return (er == eventName) /*er和eventname不能交换位置*/
          &&(pointerToCBO == er.pointerToCBO)
          &&(pointerToCBO ?
            (pointerToCBF == er.pointerToCBF):
            (pointerToCBSF == er.pointerToCBSF));
}
void EventRecord::Flush(void) 
{
    if(eventName){
      delete eventName;
      eventName = NULL;
    }
    pointerToCBO = NULL;
    pointerToCBF = NULL;
}
int EventRecord::IsEmpty(void) const
{
    if(eventName == NULL)
        return 1;
    else
        return 0;
}
  //Callback类的实现 
CallBack::CallBack(void)
{
//按初始尺寸为回调表分配内存空间
callBackList = new EventRecord[CALLBACKLIST_INIT_SIZE];
    if(!callBackList){
        cerr<<"CallBack: memory allocation error."<<endl;
        exit(1);
    }
    size = CALLBACKLIST_INIT_SIZE;
    lastpos = 0;
    curpos = 0;
}
  CallBack::CallBack(const CallBack& cb): curpos(cb.curpos),lastpos(cb.lastpos),size(cb.size) 
{
    callBackList = new EventRecord[size];
    if(!callBackList){
        cerr<<"CallBack: memory allocation error."<<endl;
        exit(1);
    }
    //一一复制各条事件记录
for(int i = 0; i < size; i++) callBackList[i] = cb.callBackList[i];
}
  void CallBack::operator = (const CallBack& cb) 
{
    curpos = cb.curpos;
    lastpos = cb.lastpos;
    size = cb.size;
      delete [] callBackList;//删除旧的回调表
    callBackList = new EventRecord[size];//重新分配内存空间
    if(!callBackList){
        cerr<<"CallBack: memory allocation error."<<endl;
        exit(1);
    }
    //一一复制各条事件记录
    for(int i = 0; i < size; i++) callBackList[i] = cb.callBackList[i];
}
  CallBack::~CallBack(void) 
{
    delete [] callBackList;
}
  void CallBack::AddCallBack(char *event, CallBackFunction pCBF, CallBack *pCBO) 
{
    //如事件名为空,退出
    if( (event == NULL)?1:(strlen(event) == 0)) return;
    //寻找因删除事件记录而产生的第一个空闲位置,并填写新事件记录
    for(int start=0;start<lastpos;start++)
        if(callBackList[start].IsEmpty()){
            callBackList[start] = EventRecord(event,pCBO,pCBF);
            break;
}
    if(start < lastpos) return; //确实存在空闲位置
    //没有空闲位置,在回调表后追加新记录
    if(lastpos == size) //回调表已满,需“伸长”
    {
        EventRecord *tempList = callBackList;//暂存旧回调表指针
        //以一定的步长“伸长”回调表
callBackList = new EventRecord[size + CALLBACKLIST_INCREMENT];
        if(!callBackList){
            cerr<<"CallBack: memory allocation error."<<endl;
            exit(1);
        }
        //复制旧回调表中的记录
        for(int i = 0; i < size; i++) callBackList[i] = tempList[i];
        delete [] tempList;//删除旧回调表
        size += CALLBACKLIST_INCREMENT;//记下新回调表的尺寸
    }
   //构造新的事件记录并将其填入回调表中
    callBackList[lastpos] = EventRecord(event,pCBO,pCBF);
    lastpos++;
}
  void CallBack::AddCallBack(char *event,CallBackStaticFunction pCBSF) 
{
    if( (event == NULL)?1:(strlen(event) == 0)) return;
    for(int start=0;start<lastpos;start++)
        if(callBackList[start].IsEmpty()){
            callBackList[start] = EventRecord(event,pCBSF);
            break;
        }
    if(start < lastpos) return; //a hole is found
      if(lastpos == size) //event list is insufficient
    {
        EventRecord *tempList = callBackList;
        callBackList = new EventRecord[size + CALLBACKLIST_INCREMENT];
  
        if(!callBackList){
            cerr<<"CallBack: memory allocation error."<<endl;
            exit(1);
        }
          for(int i = 0; i < size; i++) callBackList[i] = tempList[i];
        delete [] tempList;
        size += CALLBACKLIST_INCREMENT;
    }
  
callBackList[lastpos] = EventRecord(event,pCBSF);
lastpos++;
}
  
//删除注册在指定事件上的成员函数
void CallBack::RemoveCallBack(char *event, CallBackFunction pCBF, CallBack *pCBO)
{
    if( (event == NULL)?1:(strlen(event) == 0)) return;
    EventRecord er(event,pCBO,pCBF);
  
    for(int i = 0; i < lastpos; i++)
    if(callBackList[i] == er) callBackList[i].Flush();
}
  
//删除注册在指定事件上的静态成员函数或普通函数
void CallBack::RemoveCallBack(char *event,CallBackStaticFunction pCBSF)
{
    if( (event == NULL)?1:(strlen(event) == 0)) return;
    EventRecord er(event,pCBSF);
  
    for(int i = 0; i < lastpos; i++)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值