C++中建立物件間訊息連線的一種系統方法——回撥函式
C++中建立物件間訊息連線的一種系統方法——回撥函式作者:項飛
用過C++進行過面向物件程式設計的使用者都知道,程式中的物件很少單獨存在。不考慮物件間的相互作用幾乎是不可能的。所以,標識物件間的關係或建立物件間的訊息連線是面向物件程式設計的一項重要任務。本文著重從C++程式設計的角度,提出一種建立物件間訊息連線的實用方法。如果你想詳細瞭解面向物件程式設計技術,請參閱有關專著。大家都知道物件是資料和方法的封裝體。在C++中,它們分別表現為資料成員和成員函式。程式設計者通過執行物件的各種方法,來改變物件的狀態(即改變物件的屬性資料)。從而使該物件發生某些“事件”。當一物件發生某事件時,它通常需向其它相關物件傳送
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類的成員函式voidCallBack::CallCallBack(char *ename, CallData calldata = NULL)用來呼叫註冊在事件ename上的所有回撥函式。其中,calldata為資料指標(CallData實際上就是void*,詳見程式清單)。事件物件可通過它向回撥物件傳遞有用的資料。該成員函式通常在事件物件的成員函式中呼叫,因為通常只有事件物件的成員函式才能改變物件的內部資料,從而使某些事件發生。成員函式RemoveCallback用來刪除註冊在事件物件上的回撥函式。它的三個過載版本依次為:
void CallBack::RemoveCallBack(char*event,CallBackFunction cbf,CallBack *p);
voidCallBack::RemoveCallBack(char *event,CallBackStaticFunction cbsf);
void CallBack::RemoveCallBack(char *event);
其中,event,cbf,cbsf,p等引數和成員函式AddCallBack中各引數一樣。第一個RemoveC
allBack用於刪除註冊在事件event上某回撥物件的一個成員函式。第二個RemoveCallBa
ck用於刪除註冊在事件event上的某普通函式或某回撥類的一個靜態成員函式。第三個R
emoveCallBack用於刪除註冊在事件event上的全部回撥函式。二、CallBack類的使用方法使用CallBack類,可按以下步驟進行:
1.確定程式中哪些物件間存在關係,需要建立訊息連線。並確定在各特定訊息連線關係中,哪個物件是事件物件,哪個物件是回撥物件。
2.事件物件類和回撥物件類都必須從CallBack類繼承,以獲得回撥支援。
3.為事件物件註冊回撥資料。包括:事件名,回撥函式名,指向回撥物件的指標。
4.當你感興趣的事件發生時,在事件物件類引發事件的成員函式中呼叫CallCallBack函式。
下面是一個具體的例子。通過它你會對Callback類的使用方法有進一步的瞭解。
//測試程式檔案:test.cpp
#include"callback.h"
//“揚聲器”類
class Speaker:public CallBack
{
private:
intvolume;
public:
Speaker(intv): volume(v) {}
voidIncreaseVolume(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類,在物件間建立訊息連線已變為一項很簡單和優美的工作。