函数对象
函数对象其实就是个类对象(与仿函数差不多),只不过重载了()这个方法,而且能够保存状态(在对象内部),而且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