事件本質是回呼:元件在執行期呼叫你提供的函數,而非編譯期已知的函數呼叫。Windows 訊息迴圈、.NET 委派、C 執行期 qsort 比較函數皆屬此類。
qsort 比較函數、STL 容器自訂比較WPARAM/LPARAMvoid*__event 關鍵字 + += 註冊Visual C++ .NET 提供 __event (統一事件模型) 但有技術問題不建議使用。替代方案:介面基類。
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 解決此問題。