日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

C++中建立对象间消息连接的系统方法

發(fā)布時間:2025/3/15 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++中建立对象间消息连接的系统方法 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

  用過C++進行過面向?qū)ο蟪绦蛟O(shè)計的用戶都知道,程序中的對象很少單獨存在。不考慮對象間的相互作用幾乎是不可能的。所以,標識對象間的關(guān)系或建立對象間的消息連接是面向?qū)ο蟪绦蛟O(shè)計的一項重要任務(wù)。本文著重從C++程序設(shè)計的角度,提出一種建立對象間消息連接的實用方法。如果你想詳細了解面向?qū)ο蟪绦蛟O(shè)計技術(shù),請參閱有關(guān)專著。

  大家都知道對象是數(shù)據(jù)和方法的封裝體。在C++中,它們分別表現(xiàn)為數(shù)據(jù)成員和成員函數(shù)。程序設(shè)計者通過執(zhí)行對象的各種方法,來改變對象的狀態(tài)(即改變對象的屬性數(shù)據(jù))。從而使該對象發(fā)生某些“事件”。當一對象發(fā)生某事件時,它通常需向其它相關(guān)對象發(fā)送“消息”,請求它們作出一些處理。 這時,發(fā)生事件并向其它對象請求處理的對象被稱為“事件對象”,而處理事件的對象被稱為“回調(diào)對象”。回調(diào)對象對事件的處理稱為“回調(diào)函數(shù)”。

  在C++中,這一過程相當于:當事件對象發(fā)生事件時,調(diào)用回調(diào)對象的某些成員函數(shù)。通常的作法是回調(diào)對象向事件對象傳遞對象指針。但這種方法不通用。為了減少程序設(shè)計的工作量,本文提出一種建立對象間消息連接的系統(tǒng)方法。它的思路是:將“事件發(fā)生→請求處理→執(zhí)行處理”這一過程抽象成一個“回調(diào)”(CallBack)類。通過繼承,用戶可以輕松獲取建立對象間消息連接的機制。

  一、回調(diào)類的數(shù)據(jù)結(jié)構(gòu)及其成員函數(shù)

  本文提出的CallBack類支持三種回調(diào)函數(shù)。它們是:回調(diào)對象中的成員函數(shù),屬于回調(diào)類的靜態(tài)成員函數(shù)和普通的C函數(shù)。CallBackle類中包含一回調(diào)函數(shù)表callBackList。它用于記錄事件名稱,指向回調(diào)函數(shù)及回調(diào)對象的指針。該表的每一個節(jié)點為一個事件記錄EventRecord。每個事件記錄包含三個域:事件名指針eventName,指向回調(diào)對象的指針pointerToCBO,指向回調(diào)函數(shù)的指針pointerToCBF或pointerToCBSF(其中,pointerToCBF指向回調(diào)對象的成員函數(shù),pointerToCBSF指向回調(diào)類的靜態(tài)成員函數(shù)或普通函數(shù)。它們同處于一共用體內(nèi))。CallBack類所提供的回調(diào)機制是這樣的:在事件對象上注冊回調(diào)對象中的回調(diào)函數(shù);當事件發(fā)生時,事件對象在其回調(diào)表中檢索并執(zhí)行回調(diào)函數(shù)。從而使二者的消息連接得以建立。(關(guān)于該類的具體實現(xiàn),請參閱文后所附的程序清單) 回調(diào)對象

  事件對象

  事件名 回調(diào)對象指針 回調(diào)函數(shù)指針

“event” pointerCBO pointerToCBF或

pointerTOCBSF

- - - - - -

  AddCallBack: 注冊事件名和指向回調(diào)函數(shù),回調(diào)對象的指針

  CallCallBack: 在回調(diào)表中,檢索注冊在指定事件上回調(diào)函數(shù)并調(diào)用它們

  事件發(fā)生時,調(diào)用CallCallBack函數(shù)

  對事件event進行處理的成員函數(shù)

  從CallBack類繼承的回調(diào)表callBackList, 成員函數(shù)AddCallBack和CallCallBack。

  當回調(diào)函數(shù)為靜態(tài)成員函數(shù)或普通C函數(shù)時, pointerToCBO為NULL。

  事件名是回調(diào)表callBackLis中的檢索關(guān)鍵字。

  回調(diào)對象中其它成員函數(shù)

  CallBack類的成員函數(shù)AddCallBack用來將回調(diào)函數(shù)注冊到事件對象的回調(diào)表中。它有兩個重載版本:

void CallBack::AddCallBack(char *event,CallBackFunction cbf,CallBack *p);
void CallBack::AddCallBack(char *event,CallBackStaticFunction cbsf);

  其中,第一個AddCallBack用來將某回調(diào)對象的成員函數(shù)注冊到事件對象的回調(diào)表中。第二個AddCallBack用來將或某回調(diào)類的靜態(tài)成員函數(shù)注冊到事件對象的回調(diào)表中。在上參數(shù)表中,event是指向事件名字符串的指針,p是指向回調(diào)對象的指針,cbf和cbsf分別是指向成員函數(shù)及靜態(tài)成員函數(shù)(或普通函數(shù))的指針。當回調(diào)函數(shù)來自某回調(diào)對象SomeObject時,傳遞成員函數(shù)指針應(yīng)采用如下格式:

(CallBackFunction)&SomeObject::MemberFunctionName; 傳遞SomeObject類的某靜態(tài)成員函數(shù)指針應(yīng)采用格式:
(CallBackStaticFunction)& SomeObject::FunctionName;傳遞程序中普通函數(shù)指針時,只需傳遞函數(shù)名即可。

  CallBack類的成員函數(shù)void CallBack::CallCallBack(char *ename, CallData calldata = NULL)用來調(diào)用注冊在事件ename上的所有回調(diào)函數(shù)。其中,calldata為數(shù)據(jù)指針(CallData實際上就是void*,詳見程序清單)。事件對象可通過它向回調(diào)對象傳遞有用的數(shù)據(jù)。該成員函數(shù)通常在事件對象的成員函數(shù)中調(diào)用,因為通常只有事件對象的成員函數(shù)才能改變對象的內(nèi)部數(shù)據(jù),從而使某些事件發(fā)生。

  成員函數(shù)RemoveCallback用來刪除注冊在事件對象上的回調(diào)函數(shù)。它的三個重載版本依次為:

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等參數(shù)和成員函數(shù)AddCallBack中各參數(shù)一樣。第一個RemoveCallBack用于刪除注冊在事件event上某回調(diào)對象的一個成員函數(shù)。第二個RemoveCallBack用于刪除注冊在事件event上的某普通函數(shù)或某回調(diào)類的一個靜態(tài)成員函數(shù)。第三個RemoveCallBack用于刪除注冊在事件event上的全部回調(diào)函數(shù)。

  二、CallBack類的使用方法

  使用CallBack類,可按以下步驟進行:

  1.確定程序中哪些對象間存在關(guān)系,需要建立消息連接。并確定在各特定消息連接關(guān)系中,哪個對象是事件對象,哪個對象是回調(diào)對象。

  2.事件對象類和回調(diào)對象類都必須從CallBack類繼承,以獲得回調(diào)支持。

  3.為事件對象注冊回調(diào)數(shù)據(jù)。包括:事件名,回調(diào)函數(shù)名,指向回調(diào)對象的指針。

  4.當你感興趣的事件發(fā)生時,在事件對象類引發(fā)事件的成員函數(shù)中調(diào)用CallCallBack函數(shù)。

  下面是一個具體的例子。通過它你會對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://增加音量成員函數(shù)
  {
   volume += v;
   if(volume > 20){ file://“音量大于20”事件發(fā)生了
    file://調(diào)用注冊在兩事件上的回調(diào)函數(shù)
    CallCallBack("音量改變了");
    CallCallBack("音量大于20", &volume);
   }
  }

 void DecreaseVolume(int v) file://降低音量成員函數(shù)
 {
  volume -= v;
  if(volume < 5){ file://“音量小于5”事件發(fā)生了
   file://調(diào)用注冊在兩事件上的回調(diào)函數(shù)
   CallCallBack("音量改變了");
   CallCallBack("音量小于5", &volume);
  }
 }
};

file://“耳朵”類

class Ear : public CallBack
{
 public:
  static void Response(CallData callData) file://對“音量改變”的反應(yīng)
  {
   cout<<"音量改變了."<<endl;
  }
  void HighVoiceResponse(CallData callData)//對高音的反應(yīng)
  {
   cout<<”喂!太吵了!現(xiàn)在音量是:"<<*((int *)callData)<<endl;
  }
  void LowVoiceResponse(CallData callData)// 對低音的反應(yīng)
  {
   cout<<"啊!我聽不清了。現(xiàn)在音量是:"<<*((int *)callData)<<endl;
  }
};

void main(void)
{
 Speaker s(10); file://現(xiàn)在音量為10
 Ear e;
 file://為事件對象s注冊回調(diào)函數(shù)
 s.AddCallBack("音量大于20”,(CallBackFunction)&Ear::HighVoiceResponse,&e);
 s.AddCallBack("音量小于5”,(CallBackFunction)&Ear::LowVoiceResponse,&e);
 s.AddCallBack("音量改變了",(CallBackStaticFunction)&Ear::Response);
 s.IncreaseVolume(12);//將音量增加12,現(xiàn)在音量位22
 s.DecreaseVolume(20);//將音量減少20,現(xiàn)在音量位2
}

  運行結(jié)果:

  音量改變了.

  喂!太吵了!現(xiàn)在音量是:22

  音量改變了.

  啊!我聽不清了。現(xiàn)在音量是:2

  在上例中,揚聲器對象s為事件對象,耳朵對象e為回調(diào)對象。。s上被注冊了三個事件:“音量改變了”,“音量大于20”,“音量小于5”。 回調(diào)函數(shù)分別為:Ear::Response, Ear::HighVoiceResponse,Ear::LowVoiceResponse。當揚聲器s通過其成員函數(shù)IncreaseVolume和 DecreaseVolume改變音量時,回調(diào)對象e會自動作出反應(yīng)。可見,通過使用CallBack類,在對象間建立消息連接已變?yōu)橐豁椇芎唵魏蛢?yōu)美的工作。

  由于筆者水平有限,該類的設(shè)計必有不完善之處。如果您對它感興趣,筆者可與各位C++玩家共同探討這類問題。
附:程序清單(本程序在MS VC++5.0和TC++3.0上均編譯通過)

file://回調(diào)類的類結(jié)構(gòu):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;//回調(diào)數(shù)據(jù)指針類型定義

typedef void (CallBack::*CallBackFunction)(CallData); file://指向回調(diào)成員函數(shù)的指針

typedef void (*CallBackStaticFunction)(CallData); file://指向靜態(tài)成員函數(shù)或普通函數(shù)的指針類型定義

class EventRecord{
 private:
  char *eventName; file://回調(diào)事件名稱
  CallBack *pointerToCBO;//指向回調(diào)對象的指針
  file://指向成員函數(shù)的指針和指向靜態(tài)成員函數(shù)(或普通函數(shù))指針的共用體
  union{
   CallBackFunction pointerToCBF;
   CallBackStaticFunction pointerToCBSF;
  };
 public:
  EventRecord(void); file://事件記錄類的缺省構(gòu)造函數(shù)
  file://構(gòu)造包含成員函數(shù)的事件記錄
  EventRecord(char *ename,CallBack *pCBO,CallBackFunction pCBF);
  file://構(gòu)造包含靜態(tài)成員函數(shù)或普通函數(shù)的事件記錄
  EventRecord(char *ename,CallBackStaticFunction pCBSF);
  ~EventRecord(void);//析構(gòu)事件記錄
  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://回調(diào)事件表
  int curpos; file://當前事件記錄位置
  int lastpos; file://回調(diào)表中最后一空閑位置
  int size; file://回調(diào)表的大小

  void MoveFirst(void) { curpos = 0; }//將當前記錄置為第一條記錄
  void MoveNext(void) file://將下一條記錄置為當前記錄
  {
   if(curpos == lastpos) return;
   curpos++;
  }

  file://判斷回調(diào)表是否被遍歷完

  int EndOfList(void) const { return curpos == lastpos; }
   public:
    CallBack(void);//構(gòu)造函數(shù)
    CallBack(const CallBack& cb);//拷貝構(gòu)造函數(shù)
    ~CallBack(void);//析構(gòu)函數(shù)

  void operator = (const CallBack& cb);// 重載賦值運算符

  file://將回調(diào)對象的成員函數(shù)、靜態(tài)成員函數(shù)(或普通函數(shù)) file://注冊為事件對象的回調(diào)函數(shù)

  void AddCallBack(char *event,CallBackFunction cbf,CallBack *p);
  void AddCallBack(char *event,CallBackStaticFunction cbsf);
  file://刪除注冊在指定事件上的回調(diào)函數(shù)

  void RemoveCallBack(char *event,CallBackFunction cbf,CallBack *p);
  void RemoveCallBack(char *event,CallBackStaticFunction cbsf);
  void RemoveCallBack(char *event);// 刪除某事件的全部記錄

  file://執(zhí)行注冊在某一事件上的所有回調(diào)函數(shù)

  void CallCallBack(char *event, CallData calldata = NULL);

 };

 #endif

 file://回調(diào)類的實現(xiàn):callback.cpp

 #include"callback.h"

 file://EventRecord類的實現(xiàn)

 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類的實現(xiàn)
 CallBack::CallBack(void)
 {
  file://按初始尺寸為回調(diào)表分配內(nèi)存空間

  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://一一復(fù)制各條事件記錄
  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;//刪除舊的回調(diào)表
  callBackList = new EventRecord[size];//重新分配內(nèi)存空間
  if(!callBackList){
   cerr<<"CallBack: memory allocation error."<<endl;
   exit(1);
  }

  file://一一復(fù)制各條事件記錄

  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://尋找因刪除事件記錄而產(chǎn)生的第一個空閑位置,并填寫新事件記錄
  for(int start=0;start<lastpos;start++)
   if(callBackList[start].IsEmpty()){
    callBackList[start] = EventRecord(event,pCBO,pCBF);
    break;
   }
   if(start < lastpos) return; file://確實存在空閑位置
   file://沒有空閑位置,在回調(diào)表后追加新記錄
   if(lastpos == size) file://回調(diào)表已滿,需“伸長”
   {
    EventRecord *tempList = callBackList;//暫存舊回調(diào)表指針
    file://以一定的步長“伸長”回調(diào)表
    callBackList = new EventRecord[size + CALLBACKLIST_INCREMENT];
    if(!callBackList){
     cerr<<"CallBack: memory allocation error."<<endl;
     exit(1);
    }
    file://復(fù)制舊回調(diào)表中的記錄
    for(int i = 0; i < size; i++) callBackList[i] = tempList[i];
    delete [] tempList;//刪除舊回調(diào)表
    size += CALLBACKLIST_INCREMENT;//記下新回調(diào)表的尺寸
   }
   file://構(gòu)造新的事件記錄并將其填入回調(diào)表中
   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://刪除注冊在指定事件上的成員函數(shù)

 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://刪除注冊在指定事件上的靜態(tài)成員函數(shù)或普通函數(shù)

 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://刪除注冊在指定事件上的所有回調(diào)函數(shù)

 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://如當前事件記錄和指定事件不匹配,轉(zhuǎn)入下一條記錄繼續(xù)循環(huán)
   if(!(callBackList[curpos] == event))
   {
    MoveNext();
    continue;
   }
   file://如找到匹配記錄
   pCBO = callBackList[curpos].pointerToCBO;
   file://如事件記錄中回調(diào)對象指針為空,說明該記錄中保存的是靜態(tài)函數(shù)指針
   if(pCBO == NULL){
    pCBSF = callBackList[curpos].pointerToCBSF;
    pCBSF(callData);//調(diào)用該靜態(tài)回調(diào)函數(shù)
   }
   else file://如事件記錄中回調(diào)對象指針非空,說明該記錄中保存的是成員函數(shù)指針
   {
    pCBF = callBackList[curpos].pointerToCBF;
    (pCBO->*pCBF)(callData);// 調(diào)用該回調(diào)對象的成員函數(shù)
   }
   MoveNext();
  }
 }

總結(jié)

以上是生活随笔為你收集整理的C++中建立对象间消息连接的系统方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。