C++ 函数对象

来源:互联网 发布:苹果手机电池查询软件 编辑:程序博客网 时间:2024/06/03 19:59

函数对象:定义了调用操作符()的类对象。当用该对象调用此操作符时,其表现形式如同普通函数调用一般,因此取名叫函数对象。举个最简单的例子:

[cpp] view plain copy
  1. class A   
  2. {    
  3. public:    
  4.     int operator() ( int val )    
  5.     {    
  6.         return val > 0 ? val : -val;  
  7.     }    
  8. };    

类A中定义了操作符 ( ),A对象调用语句在形式上跟以下函数的调用完全一样:

[cpp] view plain copy
  1. int i = -1;  
  2. A func;  
  3. cout << func(i);  

与普通函数相比,函数对象比函数更加灵活,函数对象的优势:

  • 函数对象可以有自己的状态。我们可以在类中定义状态变量,这样一个函数对象在多次的调用中可以共享这个状态;
  • 函数对象有自己特有的类型。我们可以传递相应的类型作为参数来实例化相应的模板,比如说带参数的函数形参。

使用函数对象的典型例子:

1、字符串排序规则

在容器set 中对string 进行排序,首先来定义相应的类并定义 () 来规定排序规则:

[cpp] view plain copy
  1. class Sort    
  2. {    
  3. public:    
  4.     bool operator() (const string &str1, const string &str2) const  //带两个参数  
  5.     {    
  6.         return str1 > str2;    
  7.     }    
  8. };    

然后我们可以用这个类作为参数来初始化set容器:

[cpp] view plain copy
  1. set<string, Sort> myset;  //带比较函数的set构造函数,并用函数对象Sort初始化  
  2. myset.insert("A");    
  3. myset.insert("B");    

这样容器内容输出为:B,A。

2、谓词函数 

谓词函数通常用来对传进来的参数进行判断,并返回布尔值。但是一般的函数形式固化,比如字符串长度比较只能判断是否大于一个确定的长度值。函数对象可以作为谓词函数,并可以在类初始化时传递参数,如字符串长度参考值,因此函数对象比普通函数更加灵活。

现在假设我们有一串数字,要从中找出第一个不小于10的数字。可以定义如下相应的类:

[cpp] view plain copy
  1. class Upper   
  2. {    
  3. public:    
  4.     Upper(int min = 0):m_min(min){}    
  5.     bool operator() (int value) const    
  6.     {    
  7.         return value >= m_min;    
  8.     }    
  9. private:    
  10.     int m_min;    
  11. };    

从而这样调用 find_if 函数:

find_if( dest.begin(), dest.end(), Upper(10) );

首先生成类 Upper 的对象,并用 10 初始化,调用find_if 时将用该函数对象进行判断。

请注意:在调用用到函数对象的标准库算法时,除非显式地指定模板类型为传引用,否则默认情况下函数对象是按值传递的!因此,如果传递一个具有内部状态的函数对象,则被改变状态的是函数内部被复制的临时对象,函数结束后随之消失。真正传进来的函数对象状态并为改变。

[cpp] view plain copy
  1. class B  
  2. {    
  3. public:    
  4.     B(int n=0) : th(n),count(1) {}    
  5.     bool operator() (int)    
  6.     {    
  7.         return count++ == th;    
  8.     }    
  9.         
  10.     int getCount() const    
  11.     {    
  12.         return count;    
  13.     }    
  14. private:    
  15.     int th;    
  16.     int count;    
  17. };    

测试如下:

[cpp] view plain copy
  1. vector<int> vec;  
  2. forint i = 3; i!= 13; ++i )  
  3. vec.push_back(i);  
  4. B b(3);    
  5. vector<int>::iterator iter = find_if( vec.begin(), vec.end(), b ); //调用函数对象,查找第三个数字    
  6. cout<< "3rd:" << *iter <<endl;    
  7. cout<< "State:" << b.getCount() <<endl;  //指向函数对象内容,但内部值却为改变  

输出结果为,确实能找到第三个数字(5),但查看b的状态时,返回的 count 依然为0,说明:

  • 在find_if 函数执行期间,内部状态的临时对象发生改变;
  • 在函数对象调用完成后,临时对象消失,原来的状态保持不变。

原则:

不是所有的返回布尔值的函数对象都适合作为谓词函数,因此用作谓词函数的函数对象,最好不要依赖其内部状态的改变。


转载:http://blog.csdn.net/xgf415/article/details/52966475