函数对象
来源:互联网 发布: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
- 函数对象
- 函数对象
- 函数对象
- 函数对象
- 函数对象
- 函数对象
- 对象 函数
- 函数对象
- 函数对象
- 函数对象
- 函数对象
- 函数对象
- 函数对象
- 函数对象
- 函数对象
- 函数对象
- 函数对象~
- 函数对象
- 10 android编译全过程 及 单独编译Android源代码中的模块
- POJ 2115 C Looooops
- http中get与post的区别
- TrayIcon组件的使用
- linux :内核调试神器SystemTap — 简介与使用(一)
- 函数对象
- 非GUI-Qt程序运行后显示Console
- 相干带宽与相干时间
- 计算机网络---wireshark学习
- SharedPreferences
- 关于ASP.net中生成图形验证码
- 《并行程序设计导论》Peter S.Pacheco 读书笔记
- 如何成为一个牛逼的程序猿
- Leetcode: Next Permutation