我们用函数对象(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; }