程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 細說C++委托和消息反饋模板(1)

細說C++委托和消息反饋模板(1)

編輯:C++入門知識

C++實現委托消息反饋模板:

繼承+多態

乍一看是理所當然的選擇,庫中的類把響應處理函數設置為虛函數,客戶程序可以繼承這個類並且重載響應函數。以某個Socket類為例,可以提供一個OnRecv函數用來響應網絡數據包到達的處理。客戶程序只需要重載OnRecv並進行自己的處理就可以了。

  1. struct Socket { // base class  
  2. virtual void OnRecv();  
  3. };  
  4. stuct MySocket { // your event-handle class  
  5. virtual void OnRecv() { /* do sth here ... */ }  

疑問:很多時候這樣做實在很煩,特別是做小程序的時候,或者需要快速做原型的時候,一眼望去小小的程序一上來就繼承了一大堆東西,頗為不爽。只是想著能省事一點,希望能像那些腳本語言一樣快速綁定消息響應,而不是以繼承開始工作——我已經害怕看到長長的類繼承樹了,很多時候根本不必要繼承整個類;又或者某些類只提供一個接口而不是具體的類又或者需要多重繼承,處理都有一定麻煩;最麻煩的莫過於有時候需要改變響應處理,難道繼承好幾個下來麼——這麼多虛表也是浪費啊。

點評:為了使用Socket就必須繼承Socket,這可以說是Socket的設計的問題。如果需要實現類似的功能的話,可以寫成如下,雖然和繼承 Socket 沒有多少本質的差別,不過確實把消息處理類和Socket的實現扯開了。

  1. struct SocketEventHandler {  
  2. virtual void OnRecv() { /* ... */ }  
  3. virtual void OnSend() { /* ... */ }  
  4. };  
  5. struct Socket {  
  6. void set_handler( SocketEventHandler* h ) { handler_ = h; }  
  7. private:  
  8. SocketEventHandler* handler_;  
  9. };  
  10. struct MyHandler : SocketEventHandler {  
  11. void OnRecv() { ... }  
  12. };  
  13. Socket s;  
  14. MyHandler h;  
  15. s.set_handler( &h ); 

丟開繼承,我們有沒有一種簡單明確的表達方法呢?我不禁想起了c時代的回調函數……

回調函數(CallBack)

非常簡單,就是一個函數指針。剛才的OnRecv可以寫成這樣

  1. struct Socket {  
  2. void OnRecv() { if(OnRecvHandle!=NULL) OnRecvHandle(); }  
  3. void (*OnRecvHandle) ();  
  4. };  

客戶程序只需要編寫一個MyOnRecv函數,並且賦值給OnRecvHandle就可以了

  1. void MyOnRecv(); // your event-handle function  
  2. Socket foo;  
  3. foo.OnRecvHandle = MyOnRecv; 

疑問:非常簡單,不需要繼承類就可以處理,而且隨時可以替換不同的處理函數。其實多態的本質也是函數指針,只不過多態是用vtable統一管理函數指針。回調函數要特別注意函數指針是否為空的問題,因此最好外面在包裝一層判斷過程,回調函數最大問題在於類型不安全。


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved