C# 的 delegate(委託)提供了優雅的事件通知機制。在 C++ 中雖可用回調函數、消息傳遞實現類似功能,但傳統回調對面向對象支持較弱(難以綁定成員函數)。本文展示如何用模板實現類型安全、面向對象的 Delegate。
class Delegate {
public:
virtual ~Delegate() {}
virtual void operator()() = 0;
};
template <typename C>
class DelegateImpl : public Delegate {
typedef void (C::*F)();
C* m_class;
F m_fun;
public:
DelegateImpl(C* c, F f) : m_class(c), m_fun(f) {}
virtual void operator()() {
if (m_class) (m_class->*m_fun)();
}
};
class Sdk {
public:
Delegate* pEvent;
Sdk() : pEvent(nullptr) {}
void DoSomething() {
cout << "opened" << endl;
if (pEvent) (*pEvent)();
}
};
class Client {
Sdk m_sdk;
public:
Client() {
m_sdk.pEvent = new DelegateImpl<Client>(this, &Client::OnOpen);
}
void OnOpen() { cout << "event fired" << endl; }
};
為支持不同參數個數,定義宏 DEFINE_DELEGATE 自動生成對應的 Delegate 類、實現類及工廠函數:
// 0 參數
#define DEFINE_DELEGATE(NAME, R) \
class NAME##Delegate { \
public: \
virtual ~NAME##Delegate() {} \
virtual R operator()() = 0; \
}; \
template <typename C> \
class NAME##DelegateImpl : public NAME##Delegate { \
typedef R (C::*F)(); \
C* m_class; F m_fun; \
public: \
NAME##DelegateImpl(C* c, F f) : m_class(c), m_fun(f) {} \
virtual R operator()() { \
if (m_class) return (m_class->*m_fun)(); \
} \
}; \
template <typename C, typename F> \
NAME##Delegate* Make##NAME##Delegate(C* c, F f) { \
return new NAME##DelegateImpl<C>(c, f); \
}
// 1 參數、2 參數版本類似,只需在參數列表中添加 P1, P2...
DEFINE_DELEGATE(Open, void, int, string)
class Sdk {
public:
OpenDelegate* pEvent;
Sdk() : pEvent(nullptr) {}
void Open() {
cout << "opened" << endl;
if (pEvent) (*pEvent)(100, "你好");
}
};
class Client {
Sdk m_sdk;
public:
Client() {
m_sdk.pEvent = MakeOpenDelegate(this, &Client::OnOpen2);
}
void OnOpen2(int t, string str) {
cout << "event fired, Param = " << t << " param2 = " << str << endl;
}
};
new 創建 Delegate,需手動 delete,建議改用智能指針(std::unique_ptr/std::shared_ptr)std::function + lambda 或 FastDelegate 庫C++11 起推薦使用 std::function<R(Args...)> 配合 std::bind 或 lambda,標準庫實現更完善、類型安全且無需宏:
#include <functional>
class Sdk {
public:
std::function<void(int, string)> onOpen;
void Open() {
if (onOpen) onOpen(100, "你好");
}
};
class Client {
Sdk m_sdk;
public:
Client() {
m_sdk.onOpen = [this](int t, string s) { OnOpen2(t, s); };
}
void OnOpen2(int t, string s) { /* ... */ }
};
本文展示了從基礎虛函數+模板到宏擴展的 Delegate 實現演進,幫助理解 C++ 實現「可調用對象」的核心思想。實際項目中優先選用 C++11 標準庫設施。