C++中建立对象间消息连接的系统方法
下面,图老师小编带您去了解一下C++中建立对象间消息连接的系统方法,生活就是不断的发现新事物,get新技能~
本文着重从C++程序设计的角度,提出一种建立对象间消息连接的实用方法。假如你想具体了解面向对象程序设计技术,请参阅有关专著。 大家都知道对象是数据和方法的封装体。在C++中,它们分别表现为数据成员和成员函数。程序设计者通过执行对象的各种方法,来改变对象的状态(即改变对象的属性数据)。从而使该对象发生某些“事件”。当一对象发生某事件时,它通常需向其它相关对象发送“消息”,请求它们作出一些处理。 这时,发生事件并向其它对象请求处理的对象被称为“事件对象”,而处理事件的对象被称为“回调对象”。回调对象对事件的处理称为“回调函数”。 在C++中,这一过程相当于:当事件对象发生事件时,调用回调对象的某些成员函数。通常的作法是回调对象向事件对象传递对象指针。但这种方法不通用。为了减少程序设计的工作量,本文提出一种建立对象间消息连接的系统方法。它的思路是:将“事件发生→请求处理→执行处理”这一过程抽象成一个“回调”(CallBack)类。通过继续,用户可以轻松获取建立对象间消息连接的机制。 一、回调类的数据结构及其成员函数 本文提出的CallBack类支持三种回调函数。它们是:回调对象中的成员函数,属于回调类的静态成员函数和普通的C函数。CallBackle类中包含一回调函数表callBackList。它用于记录事件名称,指向回调函数及回调对象的指针。该表的每一个节点为一个事件记录EventRecord。每个事件记录包含三个域:事件名指针eventName,指向回调对象的指针pointerToCBO,指向回调函数的指针pointerToCBF或pointerToCBSF(其中,pointerToCBF指向回调对象的成员函数,pointerToCBSF指向回调类的静态成员函数或普通函数。它们同处于一共用体内)。CallBack类所提供的回调机制是这样的:在事件对象上注册回调对象中的回调函数;当事件发生时,事件对象在其回调表中检索并执行回调函数。从而使二者的消息连接得以建立。(关于该类的具体实现,请参阅文后所附的程序清单) 回调对象 事件对象 事件名 回调对象指针 回调函数指针“event” pointerCBO pointerToCBF或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类,可按以下步骤进行: 1.确定程序中哪些对象间存在关系,需要建立消息连接。并确定在各特定消息连接关系中,哪个对象是事件对象,哪个对象是回调对象。 2.事件对象类和回调对象类都必须从CallBack类继续,以获得回调支持。 3.为事件对象注册回调数据。包括:事件名,回调函数名,指向回调对象的指针。 4.当你感爱好的事件发生时,在事件对象类引发事件的成员函数中调用CallCallBack函数。 下面是一个具体的例子。通过它你会对Callback类的使用方法有进一步的了解。file://测试程序文件:test.cpp #include"callback.h"file://“扬声器”类 class Speaker:public CallBack
{
private:
int volume;
public:
Speaker(int v): volume(v) {}
void IncreaseVolume(int v) file://增加音量成员函数
{
volume += v;
if(volume 20){ file://“音量大于20”事件发生了
file://调用注册在两事件上的回调函数
CallCallBack("音量改变了");
CallCallBack("音量大于20", &volume);
}
} void DecreaseVolume(int v) file://降低音量成员函数
{
volume -= v;
if(volume 5){ file://“音量小于5”事件发生了
file://调用注册在两事件上的回调函数
CallCallBack("音量改变了");
CallCallBack("音量小于5", &volume);
}
}
};file://“耳朵”类 class Ear : public CallBack
{
public:
static void Response(CallData callData) file://对“音量改变”的反应
{
cout"音量改变了." }
void HighVoiceResponse(CallData callData)//对高音的反应
{
cout”喂!太吵了!现在音量是:"*((int *)callData) }
void LowVoiceResponse(CallData callData)// 对低音的反应
{
cout"啊!我听不清了。现在音量是:"*((int *)callData) }
};void main(void)
{
Speaker s(10); file://现在音量为10
Ear e;
file://为事件对象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类,在对象间建立消息连接已变为一项很简单和美丽的工作。 由于笔者水平有限,该类的设计必有不完善之处。假如您对它感爱好,笔者可与各位C++玩家共同探讨这类问题。 联系方式:fei_xiang@263.net
更多内容请看C/C++技术专题 C/C++进阶技术文档 系统安全设置专题,或 附:程序清单(本程序在MS VC++5.0和TC++3.0上均编译通过)file://回调类的类结构:callback.h#ifndef _CALLBACK_H#define _CALLBACK_H#includestdlib.h#includestring.h#includeiostream.h#define CALLBACKLIST_INIT_SIZE 10#define CALLBACKLIST_INCREMENT 5class CallBack;typedef void *CallData;//回调数据指针类型定义typedef void (CallBack::*CallBackFunction)(CallData); file://指向回调成员函数的指针typedef void (*CallBackStaticFunction)(CallData); file://指向静态成员函数或普通函数的指针类型定义class EventRecord{
private:
char *eventName; file://回调事件名称
CallBack *pointerToCBO;//指向回调对象的指针
file://指向成员函数的指针和指向静态成员函数(或普通函数)指针的共用体
union{
CallBackFunction pointerToCBF;
CallBackStaticFunction pointerToCBSF;
};
public:
EventRecord(void); file://事件记录类的缺省构造函数
file://构造包含成员函数的事件记录
EventRecord(char *ename,CallBack *pCBO,CallBackFunction pCBF);
file://构造包含静态成员函数或普通函数的事件记录
EventRecord(char *ename,CallBackStaticFunction pCBSF);
~EventRecord(void);//析构事件记录
void operator = (const EventRecord& er);//重载赋值运算符
file://判定当前事件记录的事件名是否为ename int operator == (char *ename) const; file://判定当前事件记录是否和指定事件记录相等 int operator == (const EventRecord& er) const; void Flush(void); file://将当前事件记录清空 int IsEmpty(void) const;//判定事件记录是否为空(即事件名是否为空) friend class CallBack; file://让CallBack类能访问EventRecord的私有成员;};class CallBack {
private:
EventRecord *callBackList; file://回调事件表
int curpos; file://当前事件记录位置
int lastpos; file://回调表中最后一空闲位置
int size; file://回调表的大小 void MoveFirst(void) { curpos = 0; }//将当前记录置为第一条记录
void MoveNext(void) file://将下一条记录置为当前记录
{
if(curpos == lastpos) return;
curpos++;
} file://判定回调表是否被遍历完 int EndOfList(void) const { return curpos == lastpos; }
public:
CallBack(void);//构造函数
CallBack(const CallBack& cb);//拷贝构造函数
~CallBack(void);//析构函数 void operator = (const CallBack& cb);// 重载赋值运算符 file://将回调对象的成员函数、静态成员函数(或普通函数) file://注册为事件对象的回调函数 void AddCallBack(char *event,CallBackFunction cbf,CallBack *p);
void AddCallBack(char *event,CallBackStaticFunction cbsf);
file://删除注册在指定事件上的回调函数 void RemoveCallBack(char *event,CallBackFunction cbf,CallBack *p);
void RemoveCallBack(char *event,CallBackStaticFunction cbsf);
void RemoveCallBack(char *event);// 删除某事件的全部记录 file://执行注册在某一事件上的所有回调函数 void CallCallBack(char *event, CallData calldata = NULL); }; #endif file://回调类的实现:callback.cpp #include"callback.h" file://EventRecord类的实现 EventRecord::EventRecord(void)
{
eventName = NULL;
pointerToCBO = NULL;
file://因为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;
} file://Callback类的实现
CallBack::CallBack(void)
{
file://按初始尺寸为回调表分配内存空间 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);
}
file://一一复制各条事件记录
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);
} file://一一复制各条事件记录 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)
{
file://如事件名为空,退出
if( (event == NULL)?1:(strlen(event) == 0)) return;
file://寻找因删除事件记录而产生的第一个空闲位置,并填写新事件记录
for(int start=0;startlastpos;start++)
if(callBackList[start].IsEmpty()){
callBackList[start] = EventRecord(event,pCBO,pCBF);
break;
}
if(start lastpos) return; file://确实存在空闲位置
file://没有空闲位置,在回调表后追加新记录
if(lastpos == size) file://回调表已满,需“伸长”
{
EventRecord *tempList = callBackList;//暂存旧回调表指针
file://以一定的步长“伸长”回调表
callBackList = new EventRecord[size + CALLBACKLIST_INCREMENT];
if(!callBackList){
cerr"CallBack: memory allocation error."endl;
exit(1);
}
file://复制旧回调表中的记录
for(int i = 0; i size; i++) callBackList[i] = tempList[i];
delete [] tempList;//删除旧回调表
size += CALLBACKLIST_INCREMENT;//记下新回调表的尺寸
}
file://构造新的事件记录并将其填入回调表中
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;startlastpos;start++)
if(callBackList[start].IsEmpty()){
callBackList[start] = EventRecord(event,pCBSF);
break;
}
if(start lastpos) return; file://a hole is found
if(lastpos == size) file://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++;
} file://删除注册在指定事件上的成员函数 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();
} file://删除注册在指定事件上的静态成员函数或普通函数 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();
} file://删除注册在指定事件上的所有回调函数 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())
{
file://如当前事件记录和指定事件不匹配,转入下一条记录继续循环
if(!(callBackList[curpos] == event))
{
MoveNext();
continue;
}
file://如找到匹配记录
pCBO = callBackList[curpos].pointerToCBO;
file://如事件记录中回调对象指针为空,说明该记录中保存的是静态函数指针
if(pCBO == NULL){
pCBSF = callBackList[curpos].pointerToCBSF;
pCBSF(callData);//调用该静态回调函数
}
else file://如事件记录中回调对象指针非空,说明该记录中保存的是成员函数指针
{
pCBF = callBackList[curpos].pointerToCBF;
(pCBO-*pCBF)(callData);// 调用该回调对象的成员函数
}
MoveNext();
}
} 更多内容请看C/C++技术专题 C/C++进阶技术文档 系统安全设置专题,
或