文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

C++程序设计如何建立对象间消息连接

2023-06-17 13:05

关注

本篇内容主要讲解“C++程序设计如何建立对象间消息连接”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++程序设计如何建立对象间消息连接”吧!

一、回调类的数据结构及其成员函数

本文提出的CallBack类支持三种回调函数。它们是:回调对象中的成员函数,属于回调类的静态成员函数和普通的C函数。CallBackle类中包含一回调函数表callBackList。它用于记录事件名称,指向回调函数及回调对象的指针。该表的每一个节点为一个事件记录EventRecord。每个事件记录包含三个域:事件名指针eventName,指向回调对象的指针pointerToCBO,指向回调函数的指针pointerToCBF或pointerToCBSF(其中,pointerToCBF指向回调对象的成员函数,pointerToCBSF指向回调类的静态成员函数或普通函数。它们同处于一共用体内)。CallBack类所提供的回调机制是这样的:在事件对象上注册回调对象中的回调函数;当事件发生时,事件对象在其回调表中检索并执行回调函数。从而使二者的消息连接得以建立。(关于该类的具体实现,请参阅文后所附的程序清单)

事件名回调对象指针回调函数指针
“event”pointerCBOpointerToCBF或pointerTOCBSF

AddCallBack: 注册事件名和指向回调函数,回调对象的指针

CallCallBack: 在回调表中,检索注册在指定事件上回调函数并调用它们

事件发生时,调用CallCallBack函数

对事件event进行处理的成员函数

从CallBack类继承的回调表callBackList, 成员函数AddCallBack和CallCallBack。

当回调函数为静态成员函数或普通C函数时, pointerToCBO为NULL。

事件名是回调表callBackLis中的检索关键字。

回调对象中其它成员函数

CallBack类的成员函数AddCallBack用来将回调函数注册到事件对象的回调表中。它有两个重载版本:

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

其中,***个AddCallBack用来将某回调对象的成员函数注册到事件对象的回调表中。第二个AddCallBack用来将或某回调类的静态成员函数注册到事件对象的回调表中。在上参数表中,event是指向事件名字符串的指针,p是指向回调对象的指针,cbf和cbsf分别是指向成员函数及静态成员函数(或普通函数)的指针。当回调函数来自某回调对象SomeObject时,传递成员函数指针应采用如下格式:(CallBackFunction)&SomeObject::MemberFunctionName; 传递SomeObject类的某静态成员函数指针应采用格式:(CallBackStaticFunction)& SomeObject::FunctionName;传递程序中普通函数指针时,只需传递函数名即可。

CallBack类的成员函数void CallBack::CallCallBack(char *ename, CallData calldata = NULL)用来调用注册在事件ename上的所有回调函数。其中,calldata为数据指针(CallData实际上就是void*,详见程序清单)。事件对象可通过它向回调对象传递有用的数据。该成员函数通常在事件对象的成员函数中调用,因为通常只有事件对象的成员函数才能改变对象的内部数据,从而使某些事件发生。

成员函数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类,可按以下步骤进行:

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

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

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

当你感兴趣的事件发生时,在事件对象类引发事件的成员函数中调用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类,在对象间建立消息连接已变为一项很简单和优美的工作。

附:程序清单(本程序在MS VC++5.0和TC++3.0上均编译通过)

//回调类的类结构: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)   &&(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++)   if(callBackList[i] == er) callBackList[i].Flush();   }   //删除注册在指定事件上的所有回调函数   void CallBack::RemoveCallBack(char *event)   {   if( (event == NULL)?1:(strlen(event) == 0)) return;   for(int i = 0; i < lastpos; i++)  if(callBackList[i] == event) callBackList[i].Flush();   }   void CallBack::CallCallBack(char *event, CallData callData)   {   if( (event == NULL)?1:(strlen(event) == 0)) return;    CallBack *pCBO;   CallBackFunction pCBF;   CallBackStaticFunction pCBSF;   MoveFirst();   while(!EndOfList())   {   //如当前事件记录和指定事件不匹配,转入下一条记录继续循环   if(!(callBackList[curpos] == event))   {   MoveNext();   continue;   }   //如找到匹配记录   pCBO = callBackList[curpos].pointerToCBO;   //如事件记录中回调对象指针为空,说明该记录中保存的是静态函数指针   if(pCBO == NULL){   pCBSF = callBackList[curpos].pointerToCBSF;   pCBSF(callData);//调用该静态回调函数   }   else //如事件记录中回调对象指针非空,说明该记录中保存的是成员函数指针   {   pCBF = callBackList[curpos].pointerToCBF;   (pCBO->*pCBF)(callData);// 调用该回调对象的成员函数   }   MoveNext();   }   }

到此,相信大家对“C++程序设计如何建立对象间消息连接”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯