.NET 中的委托是一種類型安全的函數指針,廣泛用於事件處理。在標準 C++ 中實現同樣功能並非易事,特別是對非靜態成員函數的支持。本文展示一種基於**函數對象**與**模板技術**的方案,支援靜態成員函數、非靜態成員函數及全局函數的統一回調,且嚴格保證類型安全。
委托是一個持有方法引用的類,擁有自己的簽名(返回類型、參數類型、個數),只能綁定匹配簽名的方法。它實現了「發布-訂閱」模式:提供委托的類無需知道具體有多少處理函數,只需調用委托,委托內部自動遍歷並調用所有已註冊的處理函數。
函數對象重載 operator(),使其調用語法與普通函數一致。首先定義一個基礎模板類,綁定對象指針與成員函數指針:
template <class T>
class Functor {
public:
Functor(T* pObj, int (T::*pFunc)(int))
: m_pObject(pObj), m_pFunction(pFunc) {}
int operator()(int p) {
return (m_pObject->*m_pFunction)(p);
}
private:
T* m_pObject;
int (T::*m_pFunction)(int);
};
class MyClass {
public:
int Square(int p) { return p * p; }
};
void some_function() {
MyClass theClass;
Functor<MyClass> myFunc(&theClass, &MyClass::Square);
int result = myFunc(5); // result == 25
}
為了在不知具體類型的情況下統一調用,定義一個純虛基類 FunctorBase,並令模板類繼承它:
class FunctorBase {
public:
virtual int operator()(int) = 0;
virtual ~FunctorBase() = default;
};
template <class T>
class TemplateFunctor : public FunctorBase {
public:
TemplateFunctor(T* pObj, int (T::*pFunc)(int))
: m_pObject(pObj), m_pFunction(pFunc) {}
int operator()(int p) override {
return (m_pObject->*m_pFunction)(p);
}
private:
T* m_pObject;
int (T::*m_pFunction)(int);
};
現在可以編寫接受基類指針的通用函數:
int OperateOnFunctor(int i, FunctorBase* pFunc) {
return pFunc ? (*pFunc)(i) : 0;
}
class ClassA {
public:
ClassA(int i) : m_Value(i) {}
int FuncA(int i) { return m_Value - i; }
int m_Value;
};
void test() {
ClassA a(10), b(20);
TemplateFunctor<ClassA> fa(&a, &ClassA::FuncA);
TemplateFunctor<ClassA> fb(&b, &ClassA::FuncA);
cout << OperateOnFunctor(3, &fa) << endl; // 7
cout << OperateOnFunctor(3, &fb) << endl; // 17
}
this 指針;int(int),實際專案可用模板參數化返回值與參數;此模式是現代 C++(std::function、std::bind、Lambda)的雛形,理解其原理有助於深入掌握 C++ 回調機制的本質。