1. 程式人生 > >C++中建立物件間訊息連線的一種系統方法——回撥函式

C++中建立物件間訊息連線的一種系統方法——回撥函式

C++中建立物件間訊息連線的一種系統方法——回撥函式作者:項飛

用過C++進行過面向物件程式設計的使用者都知道,程式中的物件很少單獨存在。不考慮物件間的相互作用幾乎是不可能的。所以,標識物件間的關係或建立物件間的訊息連線是面向物件程式設計的一項重要任務。本文著重從C++程式設計的角度,提出一種建立物件間訊息連線的實用方法。如果你想詳細瞭解面向物件程式設計技術,請參閱有關專著。大家都知道物件是資料和方法的封裝體。在C++中,它們分別表現為資料成員和成員函式。程式設計者通過執行物件的各種方法,來改變物件的狀態(即改變物件的屬性資料)。從而使該物件發生某些事件。當一物件發生某事件時,它通常需向其它相關物件傳送

訊息,請求它們作出一些處理。這時,發生事件並向其它物件請求處理的物件被稱為事件物件,而處理事件的物件被稱為回撥物件。回撥物件對事件的處理稱為回撥函式。在C++中,這一過程相當於:當事件物件發生事件時,呼叫回撥物件的某些成員函式。通常的作法是回撥物件向事件物件傳遞物件指標。但這種方法不通用。為了減少程式設計的工作量,本文提出一種建立物件間訊息連線的系統方法。它的思路是:將事件發生請求處理執行處理這一過程抽象成一個回撥CallBack)類。通過繼承,使用者可以輕鬆獲取建立物件間訊息連線的機制。一、回撥類的資料結構及其成員函式本文提出的CallBack類支援三種回撥函式。它們是:回撥物件中的成員函式,屬於回撥類的靜態成員函式和普通的
C函式。CallBackle類中包含一回調函式表callBackList。它用於記錄事件名稱,指向回撥函式及回撥物件的指標。該表的每一個節點為一個事件記錄EventRecord。每個事件記錄包含三個域:事件名指標eventName,指向回撥物件的指標pointerToCBO,指向回撥函式的指標pointerToCBFpointerToCBSF(其中,pointerToCBF指向回撥物件的成員函式,pointerToCBSF指向回撥類的靜態成員函式或普通函式。它們同處於一共用體內)CallBack類所提供的回撥機制是這樣的:在事件物件上註冊回撥物件中的回撥函式;當事件發生時,事件物件在其回調錶中檢索並執行回撥函式。從而使二者的訊息連線得以建立。
(關於該類的具體實現,請參閱文後所附的程式清單)回撥物件事件物件事件名回撥物件指標回撥函式指標“event”pointerCBO pointerToCBFpointerTOCBSF-- - - - -
AddCallBack:
註冊事件名和指向回撥函式,回撥物件的指標
CallCallBack:
在回調錶中,檢索註冊在指定事件上回調函式並呼叫它們
事件發生時,呼叫CallCallBack函式對事件event進行處理的成員函式CallBack類繼承的回調錶callBackList, 成員函式AddCallBackCallCallBack當回撥函式為靜態成員函式或普通C函式時, pointerToCBONULL事件名是回調錶callBackLis中的檢索關鍵字。回撥物件中其它成員函式
CallBack
類的成員函式AddCallBack用來將回調函式註冊到事件物件的回調錶中。它有兩個過載版本:
void CallBack::AddCallBack(char *event,CallBackFunction cbf,CallBack *p);
void CallBack::AddCallBack(char *event,CallBackStaticFunction cbsf);
其中,第一個AddCallBack用來將某回撥物件的成員函式註冊到事件物件的回調錶中。第二個AddCallBack用來將或某回撥類的靜態成員函式註冊到事件物件的回調錶中。在上引數表中,event是指向事件名字串的指標,p是指向回撥物件的指標,cbfcbsf分別是指向成員函式及靜態成員函式(或普通函式)的指標。當回撥函式來自某回撥物件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::HighVoiceResponseEar::LowVoiceResponse當揚聲器s通過其成員函式IncreaseVolume DecreaseVolume改變音量時,回撥物件e會自動作出反應。可見,通過使用CallBack類,在物件間建立訊息連線已變為一項很簡單和優美的工作。