函数对象

来源:互联网 发布:2017福利彩票中奖软件 编辑:程序博客网 时间:2024/06/10 18:25

      函数对象其实就是个类对象(与仿函数差不多),只不过重载了()这个方法,而且能够保存状态(在对象内部),而且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 , 另外一篇对boost::bind 与function的详细文章。http://blog.csdn.net/benny5609/article/details/2324474


其他问题:
is_move_constructible 的讨论
http://bbs.csdn.net/topics/390204835

0 0
原创粉丝点击