imjacob的专栏

首页博文目录订阅
正 文

函数指针,函数对象,闭包,命令模式之间的联系和区别(原创)

(2008-12-8 21:30)

函数指针,函数对象,闭包,命令模式这四个东西都可以作为回调使用,那他们之间的联系和区别是怎么样的呢?

1.函数指针(function pointer)很简单,就不说了。

2.函数对象(function object,functor,又译为“仿函数”)。作用和函数指针差不多,其实他一般就是伪装成函数指针,可以将函数对象作为callback传递给希望得到函数指针的例程。他比之函数指针的优点如下:提高了性能,还有可以携带状态(数据)。
网上有两片很好的文章,如下:

2.1  What are Functors ?

Functors are functions with a state. In C++ you can realize them as a class with one or more private members to store the state and with an overloaded operator () to execute the function. Functors can encapsulate C and C++ function pointers employing the concepts templates and polymorphism. You can build up a list of pointers to member functions of arbitrary classes and call them all through the same interface without bothering about their class or the need of a pointer to an instance. All the functions just have got to have the same return-type and calling parameters. Sometimes functors are also known as closures. You can also use functors to implement callbacks.

2.2  How to Implement Functors ?

First you need a base class TFunctor which provides a virtual function named Call or a virtually overloaded operator () with which you will be able to call the member function. It's up to you if you prefer the overloaded operator or a function like Call. From the base class you derive a template class TSpecificFunctor which is initialized with a pointer to an object and a pointer to a member function in its constructor. The derived class overrides the function Call and/or the operator () of the base class: In the overridden version you call the member function using the stored pointers to the object and to the member function. If you are not sure of how to use function pointers take a look at my Introduction to Function Pointers.

   //-----------------------------------------------------------------------------------------
   // 2.2 How to Implement Functors

   // abstract base class
   class TFunctor
   {
   public:

      // two possible functions to call member function. virtual cause derived
      // classes will use a pointer to an object and a pointer to a member function
      // to make the function call
      virtual void operator()(const char* string)=0;  // call using operator
      virtual void Call(const char* string)=0;        // call using function
   };


   // derived template class
   template <class TClass> class TSpecificFunctor : public TFunctor
   {
   private:
      void (TClass::*fpt)(const char*);   // pointer to member function
      TClass* pt2Object;                  // pointer to object

   public:

      // constructor - takes pointer to an object and pointer to a member and stores
      // them in two private variables
      TSpecificFunctor(TClass* _pt2Object, void(TClass::*_fpt)(const char*))
         { pt2Object = _pt2Object;  fpt=_fpt; };

      // override operator "()"
      virtual void operator()(const char* string)
       { (*pt2Object.*fpt)(string);};              // execute member function

      // override function "Call"
      virtual void Call(const char* string)
        { (*pt2Object.*fpt)(string);};             // execute member function
   };
2.3  Example of How to Use Functors

In the following example we have two dummy classes which provide a function called Display which returns nothing (void) and needs a string (const char*) to be passed. We create an array with two pointers to TFunctor and initialize the array entries with two pointers to TSpecificFunctor which encapsulate the pointer to an object and the pointer to a member ofTClassA respectively TClassB. Then we use the functor-array to call the respective member functions. No pointer to an object is needed to make the function calls and you do not have to bother about the classes anymore!

   //-----------------------------------------------------------------------------------------
   // 2.3 Example of How to Use Functors

   // dummy class A
   class TClassA{
   public:

      TClassA(){};
      void Display(const char* text) { cout << text << endl; };

      /* more of TClassA */
   };

   // dummy class B
   class TClassB{
   public:

      TClassB(){};
      void Display(const char* text) { cout << text << endl; };

      /* more of TClassB */
   };


   // main program
   int main(int /*argc*/, char* /*argv[]*/)
   {
      // 1. instantiate objects of TClassA and TClassB
      TClassA objA;
      TClassB objB;


      // 2. instantiate TSpecificFunctor objects ...
      //    a ) functor which encapsulates pointer to object and to member of TClassA
      TSpecificFunctor<TClassA> specFuncA(&objA, &TClassA::Display);

      //    b) functor which encapsulates pointer to object and to member of TClassB
      TSpecificFunctor<TClassB> specFuncB(&objB, &TClassB::Display);


      // 3. make array with pointers to TFunctor, the base class, and initialize it
      TFunctor* vTable[] = { &specFuncA, &specFuncB };


      // 4. use array to call member functions without the need of an object
      vTable[0]->Call("TClassA::Display called!");        // via function "Call"
      (*vTable[1])   ("TClassB::Display called!");        // via operator "()"


      // hit enter to terminate
      cout << endl << "Hit Enter to terminate!" << endl;
      cin.get();

      return 0;
   }
http://www.newty.de/fpt/functor.html
还有wiki上有一文:http://en.wikipedia.org/wiki/Function_object



 
3.闭包(closure),定义如下:a closure is a function that is evaluated in an environment containing one or more bound variables
其实,函数对象和闭包是一个东西??。也有一篇很好的文章:http://en.wikipedia.org/wiki/Closure_(computer_science)


后来我仔细想了一下,函数对象和闭包又不是一个东西,你在c++里听到过闭包,应该没有把(但好像0x标准会支持,这另当别论)。但在c++里一定听说过函数对象吧。
我认为函数对象(function object)有两种:
a.就是重载了函数调用操作符()。这个时候对象用起来象函数一样,其实这个时候叫仿函数(functor)才合适。
b.就是带有状态的函数。这个时候就和闭包(closure)一样了。
象命令模式里面的command,《thinking in pattern》 里就说“command 就是一个函数对象,一个被封装成对象的方法”。我想作者这里的函数对象明显是我这里说的第二个意思。
4.命令模式(command pattern)是23种模式之一,命令模式是回调机制的面向对象版本。
评 论
还没有网友评论,欢迎您第一个评论!
博 主
进入imjacob的首页
博客名称:雅克的一府
日志总数:514
评论数量:901
访问次数:1859074
建立时间:2006-11-23 20:52
导 航
公 告
Locations of visitors to this page 本博客主要用于个人学习与资料收藏。当然大家应该读了之后也能学到不少东西。其中大多数资料都是来自网络,我转载时尽可能地表明文章出处与原作者姓名,但由于很多资料经多人转载,已不清楚原作者信息与出处,所以未表明相关…
评 论
链 接

ARM+LINUX 嵌入式博客
http://blog.chinaunix.net/u1/58780/index.html

嵌入式软件
http://blog.csdn.net/embeddedsoft

诚诚恳恳做人踏踏实实编程
http://blog.sina.com.cn/u/1244756857 

和我风格相似的一个blog
http://blogger.org.cn/blog/m…