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類,在對象間建立消息連接已變爲一項很簡單和優美的工作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章