我們用函數對象(functor, function object)來實現C++中的委托。這答應一個非靜態成員函數能在特定對象的環境中被調用。我們用模板技術來保證任何類類型都能在其上使用。一個基本的函數對象(functor)定義如下:
template<class T> class Functor { public: // ConstrUCtor takes the values and stores them Functor(T *pObj, int (T::*pFunc)(int)) { m_pObject = pObj; m_pFunction = pFunc; } // Invokes the stored function intOperator ()(int p) { return (m_pObject->*m_pFunction)(p); } PRivate: T *m_pObject; // Pointer to the object int (T::*m_pFunction)(int); // Pointer to the function }; 這個函數對象(functor)使用的函數格式為:返回類型為int,帶一個類型為int的參數。操作符operator ()是函數對象的要害。它使一個函數對象(functor)使用起來和函數調用一樣。它的工作就是每次執行時調用保存在類內部的函數指針。以下代碼展示了如何使用這個函數對象(functor):
class MyClass { public: int Square(int p) { return p * p; }; };
void some_function() { // Create a class to call in the context of MyClass theClass; // Create and initialise the functor object Functor<MyClass> myFunc(&theClass, MyClass::Square); // Call the functor using the overloaded () operator int result = myFunc(5); // result will hold the value 25 } 由于重載了operator ()運算符,調用函數對象(functor)幾乎就和調用該函數本身一樣方便。這里說“幾乎”是因為指向實際對象的指針并沒有被顯示使用-它被存放在函數對象(functor)內部使用。
// Abstract base class class Functor { public: // Invoke the functor (no implementation here as it must be overridden) virtualintoperator()(int) = 0; }; 下面就是一個可以被實例化為任何類類型的模板類,假設它也有一個以一個int為參數,返回為int的函數。它是從Functor派生來的,所以一個指向特定函數對象的指針可以傳給任何一個需要其基類對象(Functor)指針的地方,所以此函數對象可以不管其真正的對象類型而被調用。除了基類和類名,這個類與之前給出的類是完全一樣的:
// Template functor template<class T> class TemplateFunctor : public Functor { public: // Constructor takes the values and stores them TemplateFunctor(T *pObj, int (T::*pFunc)(int)) { m_pObject = pObj; m_pFunction = pFunc; } // Invokes the stored function (overrides Functor::operator ()) intoperator ()(int p) { return (m_pObject->*m_pFunction)(p); } private: T *m_pObject; // Pointer to the object int (T::*m_pFunction)(int); // Pointer to the function }; 下面是一個以函數對象指針和該函數的參數為參數的簡單函數,用來調用該函數對象。注重這里以基類Functor指針而不是派生模板類指針為參數。這是必需的, 因為每一個不同的模板參數產生的模板類都是不同的類型,直接用此模板類為參數就不能支持多種類型了。
int OperateOnFunctor(int i, Functor *pFunc) { if(pFunc) return (*pFunc)(i); else return0; } 這是一個簡單的類,它包含了一個符合函數對象要求的函數-以一個int為參數并返回一個int。注重此函數還用到了一個該類的數據成員,這說明這個回調函數實際應該是在實例對象的環境下被執行的, 所以引用同一類不同對象的函數對象會產生不同的結果:
class ClassA { public: ClassA(int i) { m_Value = i; } int FuncA(int i) { return (m_Value - i); } int m_Value; }; 這是一個簡單的程序,它創建兩個引用同一類類型的函數對象的實例,針對兩個同類型的不同的對象實例調用函數對象,并顯示結果.
cout << "a gives the value " << OperateOnFunctor(5, &functorA) << endl; cout << "b gives the value " << OperateOnFunctor(5, &functorB) << endl;
return0; } 結果如下:
a gives the value 15 b gives the value 15 這個例子中,functorB調用了ClassB::FuncB,因此結果是(10+5)。注重我們幾乎用同樣的方式把兩個函數對象傳給了OperateOnFunctor)。是基類Functor的設計提供了我們這種方便性。 用宏參數化函數對象
Collapse #define DECLARE_FUNCTOR(name, parmdecl, parmcall) / /* A function object base class for this parameter list */ / class name##Functor / { / public: / virtualvoidoperator () parmdecl = 0; / }; / / /* Template class derived from Functor for / make class-specific function objects */ / template<class C> / class name##TFunctor : public name##Functor / { / public: / /* Only constructor - stores the given data */ / name##TFunctor(C* pObj, void (C::*pFunc)parmdecl) / { / m_pObj = pObj; / m_pFunc = pFunc; / } / / /* Invokes the function object with the given parameters */ / voidoperator ()parmdecl { (m_pObj->*m_pFunc)parmcall; } / C *m_pObj; /* Object pointer */ / void (C::*m_pFunc)parmdecl; /* Method pointer */ / }; 3個宏參數的意義如下:
name -函數對象的名字。Functor基類會加上“Functor“的后綴, 而模板類會加上”TFunctor“的后綴。
parmdecl -操作符operator()的參數列表聲明.列表必須包括在小括號對里面
parmcall -傳給內部函數的實參列表。以下例子可以很好的解釋這兩個列表的關系:
使用該宏的例子:
DECLARE_FUNCTOR(Add, (int p1, int p2), (p1, p2)) 定義了一個以2個int為參數函數對象AddFunctor。宏展開后代碼如下(當然, 事實上它們應該在一行上,并且沒有注釋)
Collapse /* A function object base class for this parameter list */ class AddFunctor { public: virtualvoidoperator () (int p1, int p2) = 0; };
/* Template class derived from AddFunctor for make class-specific function objects */ template<class C> class AddTFunctor : public AddFunctor { public: /* Only constructor - stores the given data */ AddTFunctor(C* pObj, void (C::*pFunc)(int p1, int p2)) { m_pObj = pObj; m_pFunc = pFunc; }
/* Invokes the function object with the given parameters */ voidoperator ()(int p1, int p2) { (m_pObj->*m_pFunc)(p1, p2); } C *m_pObj; /* Object pointer */ void (C::*m_pFunc)(int p1, int p2); /* Method pointer */ }; 正如你所看到的,在所有name出現的地方都被“Add“所代替, parmdecl則被(int P1, int p2)替換, 而parmcall則被(p1, p2)替換)。為了更好的體現parmdecl和parmcall的關系,看以下operator()操作符,第一行是宏, 第二行是展開后的代碼:
int main() { // Create class instances A a; B b; // Create an instance of the delegate AddDelegate::Delegate del; // Add our handlers del += AddHandler(&a, A::Fun1); // or del.Add(&a, A::Fun1); del += AddHandler(&b, B::Fun1); // or del.Add(&b, B::Fun2); del += GlobalFunc; // or del.Add(GlobalFunc); del += A::StaticFunc; // or del.Add(A::StaticFunc); // Invoke the delegate del(4, 5); // or del.Invoke(4, 5); // Print the class values cout << "[main] a.value = " << a.value << endl; cout << "[main] b.value = " << b.value << endl; // Remove some of the handlers del -= AddHandler(&a, A::Fun1); // or del.Remove(&a, A::Fun1); del -= A::StaticFunc; // or del.Remove(A::StaticFunc); // Invoke the delegate again del(4, 5); // or del.Invoke(4, 5); // Print the class values cout << "[main] a.value = " << a.value << endl; cout << "[main] b.value = " << b.value << endl; return0; } 這個例子展示了委托幾乎所有的操作,其結果如下:
Method: template<class C> void Delegate::Add(C *pObj, void (C::*pFunc)(<parameters>)) Description: Adds a callback function that is a non-static member function of a class. The member function must return void and take a parameter list that is the same as <parameters>. Return value: void - nothing. Parameters: pObj - A pointer to the object to call the callback method in the context of. pFunc - A pointer to the callback method to call.
Method: void Delegate::Add(void (*pFunc)(<parameters>)) Description: Adds a callback function that is either a static member function of a class or is not a class member function. The function must return void and take a parameter list that is the same as <parameters>. Return value: void - nothing. Parameters: pFunc - A pointer to the callback function to call.
Method: template<class C> void Delegate::Remove(C *pObj, void (C::*pFunc)parmdecl) Description: Removes a callback function from the callback function list Return value: void - nothing. Parameters: pObj - A pointer to the object that is being referred to. pFunc - A pointer to the callback method being referred to. These two parameters together specify the callback handler to be removed.
Method: void Delegate::Remove(void (*pFunc)parmdecl) Description: Removes a callback function from the callback function list Return value: void - nothing. Parameters: pFunc - A pointer to the callback method being referred to.
Method: void Delegate::operator +=(Functor *pFunc) Description: Adds a callback function that is a non-static member function of a class. The member function must return void and take a parameter list that is the same as <parameters>. Return value: void - nothing. Parameters: pFunc - A pointer to the functor to call. This should be created using the <name>Handler() function.
Method: void Delegate::operator +=(void (*pFunc)(<parameters>)) Description: Adds a callback function that is either a static member function of a class or is not a class member function. The function must return void and take a parameter list that is the same as <parameters>. Return value: void - nothing. Parameters: pFunc - A pointer to the callback function to call.
Method: void Delegate::operator -=(Functor *pFunc) Description: Removes a callback function that is a non-static member function of a class. Return value: void - nothing. Parameters: pFunc - A pointer to the functor to remove. This should be created using the <name>Handler() function, and is deleted by the function.
Method: void Delegate::operator -=(void (*pFunc)(<parameters>)) Description: Removes a callback function that is either a static member function of a class or is not a class member function. Return Value: void - nothing. Parameters: pFunc - A pointer to the callback function to remove.
Method: void Delegate::Invoke(<parameters>) Description: Calls all the callbacks in the callback list with the specified parameters. Return Value: void - nothing. Parameters: <parameters> - The parameters to pass to the callback functions, as specified in the parameter to DECLARE_DELEGATE().
Method: void Delegate::operator ()(<parameters>) Description: Calls all the callbacks in the callback list with the specified parameters Return Value: void - nothing. Parameters: <parameters> - The parameters to pass to the callback functions, as specified in the parameter to DECLARE_DELEGATE(). 后續功能
/////////////////////////////////////////////////////////////////////////// // delegate.h // Interface/implementation of the delegate classes and macros /////////////////////////////////////////////////////////////////////////// // Author: Ryan Binns // Changelog: // 19-Aug-2003 : Initial Release ///////////////////////////////////////////////////////////////////////////
#ifndef DELEGATE_H__ #define DELEGATE_H__
// This STL include file removes the STL warning when the compiler // is set to warning level 4. It was written by Oskar Wieland, and // is available at: // http://www.codeproject.com/vcpp/stl/stl_without_warnings.asp #define STL_USING_VECTOR /* * Here, for convenience, I just ignore this header file but put the code directly. */ //#include "stl.h" #ifdef STL_USING_VECTOR
#pragma warning(push)
#include <yvals.h> // warning numbers get enabled in yvals.h
#pragma warning(disable: 4018) // signed/unsigned mismatch #pragma warning(disable: 4100) // unreferenced formal parameter #pragma warning(disable: 4245) // conversion from 'type1' to 'type2', signed/unsigned mismatch #pragma warning(disable: 4663) // C++ language change: to eXPlicitly specialize class template 'vector' #pragma warning(disable: 4702) // unreachable code #pragma warning(disable: 4710) // 'function' : function not inlined #pragma warning(disable: 4786) // identifier was truncated to 'number' characters in the debug information
#include <vector>
#pragma warning(pop)
#endif
// Declares a delegate // name - gives the beginning of the name of the delegate namespace, so // DECLARE_DELEGATE(Add, ..., ...) would make a namespace // called "AddDelegate" which contains the Add delegate classes. // parmdecl - is the declaration of the parameters in the callbacks // (surrounded by brackets), such as "(int val1, int val2)" // parmcall - is how the parameters are called (surrounded in brackets), // such as "(var1, var2)" // so: DECLARE_DELEGATE(Add, (int val1, int val2), (val1, val2)) // would declare a delegate called AddDelegate, that takes two int // parameters (the parameter names are not important). #define DECLARE_DELEGATE(name, parmdecl, parmcall) namespace name##Delegate { class Delegate; /* Forward declaration */ /* A function object base class for this parameter list */ class Functor { public: virtual void Invoke parmdecl = 0; virtual bool isMethod() = 0; virtual bool operator ==(Functor *pf) = 0; };
/* Template class derived from Functor for making class-specific function objects */ template<class C> class TFunctor : public Functor { public: /* Only constructor - stores the given data */ TFunctor(C* pObj, void (C::*pFunc)parmdecl) { m_pObj = pObj; m_pFunc = pFunc; } bool isMethod() { return true; } bool operator ==(Functor *pf) { if(!pf->isMethod()) return false; TFunctor<C> *pf1 = (TFunctor<C>*)pf; if((pf1->m_pObj == m_pObj) && (pf1->m_pFunc == m_pFunc)) return true; else return false; }
/* Invokes the function object with the given parameters */ void Invoke parmdecl { (m_pObj->*m_pFunc)parmcall; } private: C *m_pObj; /* Object pointer */ void (C::*m_pFunc)parmdecl; /* Method pointer */ };
/* Class for function function objects */ class FFunctor : public Functor { public: /* Only constructor - stores the given data */ FFunctor(void (*pFunc)parmdecl) { m_pFunc = pFunc; } bool isMethod() { return false; } bool operator ==(Functor *pf) { if(pf->isMethod()) return false; FFunctor *pf1 = (FFunctor*)pf; if(pf1->m_pFunc == m_pFunc) return true; else return false; }
/* Invokes the function object with the given parameters */ void Invoke parmdecl { m_pFunc parmcall; } private: void (*m_pFunc)parmdecl; /* Function pointer */ };
/* Calls all the callbacks in the callback list */ void Invoke parmdecl { for(vit i=m_pFuncs.begin(); i!=m_pFuncs.end(); i++) (*i)->Invoke parmcall; } /* Calls all the callbacks in the callback list */ void operator ()parmdecl { Invoke parmcall; }
private: /* List of callback functions */ std::vector<Functor*> m_pFuncs; /* typedef'd iterator */ typedef std::vector<Functor*>::iterator vit; }; }
unsigned char *RowCnt) { unsigned short result; __asm { mov ax, 1416h int 10h mov result, cx les edi, ColCnt mov es:[edi], bl //error illegal reference to 16-bit data in 'first operand’ les di, RowCnt mov es:[edi], bh // the same problem } return(result); }
int main() { // Create class instances A a; B b; // Create an instance of the delegate AddDelegate::Delegate del; // Add our handlers del += AddHandler(&a, &A::Fun1); // or del.Add(&a, A::Fun1); del += AddHandler(&b, &B::Fun1); // or del.Add(&b, B::Fun2); del += GlobalFunc; // or del.Add(GlobalFunc); del += A::StaticFunc; // or del.Add(A::StaticFunc); // Invoke the delegate del(4, 5); // or del.Invoke(4, 5); // Print the class values cout << "[main] a.value = " << a.value << endl; cout << "[main] b.value = " << b.value << endl; // Remove some of the handlers del -= AddHandler(&a, &A::Fun1); // or del.Remove(&a, A::Fun1); del -= A::StaticFunc; // or del.Remove(A::StaticFunc); // Invoke the delegate again del(4, 5); // or del.Invoke(4, 5); // Print the class values cout << "[main] a.value = " << a.value << endl; cout << "[main] b.value = " << b.value << endl; return 0; }