函数对象

函数对象其实就是个类对象(与仿函数差不多),只不过重载了()这个方法,而且能够保存状态(在对象内部),而且c++好多stl接口都支持(一个优势,for_each),而且c++提供了构造函数对象的方法(不必去写一个仿函数,可以用Lambda表达式构造,可以用mem_fun_ref或者mem_fun构造,也可以用boost::bind()构造)。关于lambda表达式可以参考:http://msdn.microsoft.com/en-us/library/vstudio/dd293608(v=vs.110).aspx其中介绍时候说“It does this by defining a class and constructing an object of that type”,实现机理应该也是函数对象,关于函数指针,函数对象,lambda表达式的优缺点如下:

A lambda combines the benefits of function pointers and function objects and avoids their disadvantages. Like a function objects, a lambda is flexible and can maintain state, but unlike a function object, its compact syntax doesn’t require a class definition. By using lambdas, you can write code that’s less cumbersome and less prone to errors than the code for an equivalent function object.

msdn的一个简单例子,使用mem_fun_ref实现http://msdn.microsoft.com/en-us/library/741a5f2d(v=vs.100).aspx 以前的一个仿函数例子http://blog.csdn.net/ysu108/article/details/9001347 上面两个例子主要是函数对象的使用,简单坐下注释,首先要了解下for_each这个函数参考:http://www.cplusplus.com/reference/algorithm/for_each/?kw=for_each官网上说,这个函数模板等价于:

template<class InputIterator, class Function>
  Function for_each(InputIterator first, InputIterator last, Function fn)
{
  while (first!=last) {
    fn (*first);
    ++first;
  }
  return fn;      // or, since C++11: return move(fn);
}

看下这个函数的第三个参数:

Unary function that accepts an element in the range as argument. This can either be a function pointer or a move constructible function object. Its return value, if any, is ignored.”

也就是所这个参数可以是个函数对象。

// functional_mem_fun_ref.cpp
// compile with: /EHsc
#include <vector>
#include <functional>
#include <algorithm>
#include <iostream>

using namespace std;

class NumVals
   {
   int val;
   public:
   NumVals ( ) { val = 0; }
   NumVals ( int j ) { val = j; }

   bool display ( ) { cout << val << " "; return true; }
   bool isEven ( ) { return ( bool )  !( val %2 ); }
   bool isPrime( )
   {
      if (val < 2) { return true; }
      for (int i = 2; i <= val / i; ++i)
      {
         if (val % i == 0) { return false; }
      }
      return true;
   }
};

int main( )
{
   vector <NumVals> v1 ( 13 ), v2 ( 13 );
   vector <NumVals>::iterator v1_Iter, v2_Iter;
   int i, k;

   for ( i = 0; i < 13; i++ ) v1 [ i ] = NumVals ( i+1 );
   for ( k = 0; k < 13; k++ ) v2 [ k ] = NumVals ( k+1 );

   cout << "The original values stored in v1 are: " ;
   for_each( v1.begin( ), v1.end( ), 
   mem_fun_ref ( &NumVals::display ) );
   cout << endl;

   // Use of mem_fun_ref calling member function through a reference
   // remove the primes in the vector using isPrime ( )
   v1_Iter = remove_if ( v1.begin( ),  v1.end( ), 
      mem_fun_ref ( &NumVals::isPrime ) ); 
   // 这里面的isPrime是有类的成员函数,是有个隐形的this参数的
   // 其实这个里面等价于&NumVals::isPrime(NumVals* this),这里看起来有些别扭
   
   cout << "With the primes removed, the remaining values in v1 are: " ;
   for_each( v1.begin( ), v1_Iter, 
   mem_fun_ref ( &NumVals::display ) );
   cout << endl;

   cout << "The original values stored in v2 are: " ;
   for_each( v2.begin( ), v2.end( ), 
   mem_fun_ref ( &NumVals::display ) );
   cout << endl;

   // Use of mem_fun_ref calling member function through a reference
   // remove the even numbers in the vector v2 using isEven ( )
   v2_Iter = remove_if ( v2.begin( ),  v2.end( ), 
      mem_fun_ref ( &NumVals::isEven ) );   
   cout << "With the even numbers removed, the remaining values are: " ;
   for_each( v2.begin( ),  v2_Iter, 
   mem_fun_ref ( &NumVals::display ) );
   cout << endl;
}

The original values stored in v1 are: 1 2 3 4 5 6 7 8 9 10 11 12 13 
With the primes removed, the remaining values in v1 are: 4 6 8 9 10 12 
The original values stored in v2 are: 1 2 3 4 5 6 7 8 9 10 11 12 13 
With the even numbers removed, the remaining values are: 1 3 5 7 9 11 13 

如果使用boost库,相比lambda表达式,易读性会好很多,参考:http://blog.csdn.net/hopingwhite/article/details/6278472如果想保存下boost::bind()后生成的函数对象,那么可以使用function把生成的临时函数对象保存起来,这样有两个特别的功能,一是可以切换线程的上下文,在一个线程中绑定,在另外一个线程中执行。二是可以反复使用。

class X{ 
public: 
    int foo(int a) 
    { 
        cout << a <<endl; 
        return a; 
    } 
};
int _tmain(int argc, _TCHAR* argv[]) 
{ 
    // 这里注意X*为this指针,要显示传递。
    boost::function<int(X*, int)>f;
    f = &X::foo;
    X x; 
    f(&x, 5);
 
 //也可以直接使用
 X* pX = new X;
 boost::bind(&X::foo, pX, a);
 
 // 也可以使用
 X x;
 boost::bind(&X::foo, x, a);
 
    return 0; 
}

上面的boost::bind(&X::foo,x,a);需要注意,传的为一个实际的对象,这样的话会有很多的拷贝构造工作(14次左右)来保存临时对象x。使用指针拷贝操作少但是释放是个问题,最好的方法是使用智能指针。其他除了this指针外的参数如果是指针也要注意释放问题。还有个问题,如果参数为一个引用,那么内部应该是个拷贝构造出来的,可以为引用类型,但是考虑模板实现的话内部不大可能是引用,因为如果定义个模板类,里面有T &m; 引用定义的时候一定要初始化。?待定

之所以是bind,“绑定”,而不是make,factory什么的,我理解这个函数的重心不是“创建了一个函数对象”,而是把原来的函数与这个临时的函数对象关联起来,也就是突出了主要的职责。

参考:

http://blog.csdn.net/starlee/article/details/1400811
http://blog.csdn.net/starlee/article/details/1400811

Table of Contents