首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

事件程式設計 (一):從基本概念到 C++ 實作

     編輯:關於VC++

什麼是事件?

事件本質是回呼:元件在執行期呼叫你提供的函數,而非編譯期已知的函數呼叫。Windows 訊息迴圈、.NET 委派、C 執行期 qsort 比較函數皆屬此類。

事件 vs 異常

  • 異常:非預期錯誤 (記憶體不足、除零),堆疊展開銷毀物件
  • 事件:預期常態操作 (滑鼠移動、瀏覽器導航),同步函數呼叫,控制權移交處理器直到完成

何時使用事件

  1. 通知實際事件:按鍵、午夜、風扇故障
  2. 回報耗時操作進度:檔案複製、資料庫搜尋
  3. 報告重要狀態變更:IE 導航、新視窗建立
  4. 呼叫應用程式演算法:qsort 比較函數、STL 容器自訂比較

Windows 事件機制缺點

  • 僅透過視窗程序與固定 WPARAM/LPARAM
  • 每視窗僅一視窗程序,多重接收需子類化鏈結
  • 非真正事件系統:無法同層級多重註冊

.NET 事件模型

  • 任意物件定義事件,多物件監聽
  • 委派型別安全,無 void*
  • __event 關鍵字 + += 註冊

原生 C++ 實作事件

Visual C++ .NET 提供 __event (統一事件模型) 但有技術問題不建議使用。替代方案:介面基類。

範例:CPrimeCalculator

class IPrimeEvents
{
public:
    virtual void OnProgress(UINT nPrimes) = 0;
    virtual void OnDone() = 0;
};

class CPrimeCalculator
{
    list<IPrimeEvents*> m_clients;
public:
    void Register(IPrimeEvents* p) { m_clients.push_back(p); }
    void Unregister(IPrimeEvents* p) { m_clients.remove(p); }
    
    void FindPrimes(UINT max)
    {
        for (UINT p = 2; p < max; p++)
        {
            if (IsPrime(p))
            {
                if (ShouldReport()) NotifyProgress(GetPrimeCount());
            }
        }
        NotifyDone();
    }
    
    void NotifyProgress(UINT nFound)
    {
        for (auto it = m_clients.begin(); it != m_clients.end(); ++it)
            (*it)->OnProgress(nFound);
    }
    
    void NotifyDone()
    {
        for (auto it = m_clients.begin(); it != m_clients.end(); ++it)
            (*it)->OnDone();
    }
};

客戶端使用

class CMyDlg : public CDialog, public IPrimeEvents
{
    void OnProgress(UINT n) override { /* 更新 UI */ }
    void OnDone() override { /* 完成處理 */ }
};

// 註冊
calculator.Register(this);

多重客戶端示範

測試程式 PrimeCalc 實作兩個處理器:主對話框顯示進度,CTracePrimeEvents 輸出診斷追蹤。

現有實作缺點

  • 每個事件需寫 NotifyFoo,模式固定重複
  • 事件介面與事件源耦合,難以重用

下篇將以仿函數、模板與巨集封裝通用 CEventMgr 解決此問題。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved