| 導購 | 订阅 | 在线投稿
分享
 
 
當前位置: 王朝網路 >> c/c++ >> C++中建立對象間消息連接的系統方法
 

C++中建立對象間消息連接的系統方法

2008-06-01 02:07:31  編輯來源:互聯網  简体版  手機版  評論  字體: ||
 
 
  用過C++進行過面向對象程序設計的用戶都知道,程序中的對象很少單獨存在。不考慮對象間的相互作用幾乎是不可能的。所以,標識對象間的關系或建立對象間的消息連接是面向對象程序設計的一項重要任務。

   本文著重從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

  #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); 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;start<lastpos;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;start<lastpos;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++進階技術文檔 系統安全設置專題,

  

   或
 
 
 
上一篇《創世紀的C++ Builder--入門例子》
下一篇《C++/CLI實戰——HELLO》
 
 
 
 
 
 
日版寵物情人插曲《Winding Road》歌詞

日版寵物情人2017的插曲,很帶節奏感,日語的,女生唱的。 最後聽見是在第8集的時候女主手割傷了,然後男主用嘴幫她吸了一下,插曲就出來了。 歌手:Def...

兄弟共妻,我成了他們夜裏的美食

老鍾家的兩個兒子很特別,就是跟其他的人不太一樣,魔一般的執著。兄弟倆都到了要結婚的年齡了,不管自家老爹怎麽磨破嘴皮子,兄弟倆說不娶就不娶,老父母爲兄弟兩操碎了心...

如何磨出破洞牛仔褲?牛仔褲怎麽剪破洞?

把牛仔褲磨出有線的破洞 1、具體工具就是磨腳石,下面墊一個硬物,然後用磨腳石一直磨一直磨,到把那塊磨薄了,用手撕開就好了。出來的洞啊很自然的。需要貓須的話調幾...

我就是掃描下圖得到了敬業福和愛國福

先來看下敬業福和愛國福 今年春節,支付寶再次推出了“五福紅包”活動,表示要“把欠大家的敬業福都還給大家”。 今天該活動正式啓動,和去年一樣,需要收集“五福”...

冰箱異味産生的原因和臭味去除的方法

有時候我們打開冰箱就會聞到一股異味,冰箱裏的這種異味是因爲一些物質發出的氣味的混合體,聞起來讓人惡心。 産生這些異味的主要原因有以下幾點。 1、很多人有這種習...

《極品家丁》1-31集大結局分集劇情介紹

簡介 《極品家丁》講述了現代白領林晚榮無意回到古代金陵,並追隨蕭二小姐化名“林三”進入蕭府,不料卻陰差陽錯上演了一出低級家丁拼搏上位的“林三升職記”。...

李溪芮《極品家丁》片尾曲《你就是我最愛的寶寶》歌詞

你就是我最愛的寶寶 - 李溪芮 (電視劇《極品家丁》片尾曲) 作詞:常馨內 作曲:常馨內 你的眉 又鬼馬的挑 你的嘴 又壞壞的笑 上一秒吵鬧 下...

烏梅的功效與作用以及烏梅的食用禁忌有哪些?

烏梅,又稱春梅,中醫認爲,烏梅味酸,性溫,無毒,具有安心、除熱、下氣、祛痰、止渴調中、殺蟲的功效,治肢體痛、肺痨病。烏梅泡水喝能治傷寒煩熱、止吐瀉,與幹姜一起制...

什麽是脂肪粒?如何消除臉部脂肪粒?

什麽是脂肪粒 在我們的臉上總會長一個個像脂肪的小顆粒,弄也弄不掉,而且顔色還是白白的。它既不是粉刺也不是其他的任何痘痘,它就是脂肪粒。 脂肪粒雖然也是由油脂...

網絡安全治理:國家安全保障的主要方向是打擊犯罪,而不是處置和懲罰受害者

來源:中國青年報 新的攻擊方法不斷湧現,黑客幾乎永遠占據網絡攻擊的上風,我們不可能通過技術手段杜絕網絡攻擊。國家安全保障的主要方向是打擊犯罪,而不是處置和懲罰...

河南夫妻在溫嶺網絡直播“造人”內容涉黃被刑事拘留

夫妻網絡直播“造人”爆紅   1月9日,溫嶺城北派出所接到南京警方的協查通告,他們近期打掉了一個涉黃直播APP平台。而根據掌握的線索,其中有一對涉案的夫妻主播...

如何防止牆紙老化?牆紙變舊變黃怎麽辦?

如何防止牆紙老化? (1)選擇透氣性好的牆紙 市場上牆紙的材質分無紡布的、木纖維的、PVC的、玻璃纖維基材的、布面的等,相對而言,PVC材質的牆紙最不透氣...

鮮肌之謎非日本生産VS鮮肌之謎假日貨是謠言

觀點一:破日本銷售量的“鮮肌之謎” 非日本生産 近一段時間,淘寶上架了一款名爲“鮮肌之謎的” 鲑魚卵巢美容液,號稱是最近日本的一款推出的全新護膚品,産品本身所...

中國最美古詩詞精選摘抄

系腰裙(北宋詞人 張先) 惜霜蟾照夜雲天,朦胧影、畫勾闌。人情縱似長情月,算一年年。又能得、幾番圓。 欲寄西江題葉字,流不到、五亭前。東池始有荷新綠,尚小如...

關于女人的經典語句

關于女人的經典語句1、【做一個獨立的女人】 思想獨立:有主見、有自己的人生觀、價值觀。有上進心,永遠不放棄自己的理想,做一份自己喜愛的事業,擁有快樂和成就...

未來我們可以和性愛機器人結婚嗎?

你想體驗機器人性愛嗎?你想和性愛機器人結婚嗎?如果你想,機器人有拒絕你的權利嗎? 近日,第二屆“國際人類-機器人性愛研討會”大會在倫敦金史密斯大學落下帷幕。而...

全球最變態的十個地方

10.土耳其地下洞穴城市 變態指數:★★☆☆☆ 這是土耳其卡帕多西亞的一個著名景點,傳說是當年基督教徒們爲了躲避戰爭而在此修建。裏面曾住著20000人,...

科學家稱,人類死亡後意識將在另外一個宇宙中繼續存活

據英國《每日快報》報道,一位科學家兼理論家Robert Lanza博士宣稱,世界上並不存在人類死亡,死亡的只是身體。他認爲我們的意識借助我們體內的能量生存,而且...

《屏裏狐》片頭曲《我愛狐狸精》歌詞是什麽?

《我愛狐狸精》 - 劉馨棋   (電視劇《屏裏狐》主題曲)   作詞:金十三&李旦   作曲:劉嘉   狐狸精 狐狸仙   千年修...

 
 
 
  用過C++進行過面向對象程序設計的用戶都知道,程序中的對象很少單獨存在。不考慮對象間的相互作用幾乎是不可能的。所以,標識對象間的關系或建立對象間的消息連接是面向對象程序設計的一項重要任務。 本文著重從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 #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); 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;start<lastpos;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;start<lastpos;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++進階技術文檔 系統安全設置專題, 或
󰈣󰈤
 
 
 
  免責聲明:本文僅代表作者個人觀點,與王朝網路無關。王朝網路登載此文出於傳遞更多信息之目的,並不意味著贊同其觀點或證實其描述,其原創性以及文中陳述文字和內容未經本站證實,對本文以及其中全部或者部分內容、文字的真實性、完整性、及時性本站不作任何保證或承諾,請讀者僅作參考,並請自行核實相關內容。
 
 
陽光靓麗的模特兒(8)
陽光靓麗的模特兒(7)
陽光靓麗的模特兒(6)
陽光靓麗的模特兒(5)
秋-印象
德慶盤龍峽 一
松江印象之三
雲之南(寬幅)
 
>>返回首頁<<
 
 
 
 熱帖排行
 
 
 
 
© 2005- 王朝網路 版權所有