函数对象

来源:互联网 发布:炉石传说淘宝刷金币 编辑:程序博客网 时间:2024/06/05 02:41

  如果一个类中实现了重载括号()运算符,即operator(),那么这个类的对象就是一个函数对象。因为函数对象实现了operator(),所以它就有了类似函数的行为,可以像函数一样来调用它,所以函数对象又称为仿函数:

class CSquare{public:void operator()(int& x){x = x * x;} };int main(){int n = 5;CSquare()(n);cout << n << endl; //输出为25return 0;}

  谓词就是函数或函数对象,并且它的调用返回值是一个能用作条件的值,比如bool。一元谓词就是带一个参数的函数,二元谓词就是带两个参数的函数。

1、sort()、stable_sort()、unique()

  一些STL算法都会比较输入容器中的元素来完成功能,默认情况下是使用<或==运算符完成比较,如sort算法默认使用元素类型的<运算符,得到的排序结果是升序的。如果我们希望排序结果与<所定义的顺序不同,就需要使用可调用对象来自定义比较,而且可调用对象所使用的输入容器的元素类型必须能够转化为函数对象的operator()参数类型。可调用对象有四种:函数、函数指针、重载了调用运算符(operator())的类、lambda表达式。

比如我们想要sort实现降序排序的话可以自己定义函数或函数对象来传入:

bool myFunction(int i, int j) { return (i > j); }class myClass {public:bool operator() (int i, int j) { return (i > j); }};int main(){vector<int> v = list_of(5) (2) (4) (3) (5);sort(v.begin(), v.end(), myClass()/*myFunction*/);for (auto iter = v.begin(); iter != v.end(); iter++)cout << *iter << endl;return 0;}

STL有一组预定义的函数对象模板,如equal<T>、less<T>、less_equal<T>、greater<T>等。如果容器元素是int、float、string等标准类型,就可以直接使用它们来创建一个二元谓词,从而不必自己再定义,eg:

int main(){vector<int> v = list_of(5) (2) (4) (3) (5);sort(v.begin(), v.end(), greater<int>());for (auto iter = v.begin(); iter != v.end(); iter++)cout << *iter << endl;return 0;}
对于排序还有一个算法stable_sort(),它是将符合相等条件的元素按照原来的顺序存放,比对对于一个vector<string>,我们想按照每个元素的长度来升序排序,那么

传入的函数对象应该是这样:

class CCompare{public:bool operator()(const string& str1, const string& str2){return str1.length() < str2.length();}};int main(){vector<string> vc;vc.push_back("abc");vc.push_back("ab");vc.push_back("ac");vc.push_back("a");sort(vc.begin(), vc.end(), CCompare());for (auto iter = vc.begin(); iter != vc.end(); iter++)cout << *iter << endl;return 0;}
可以看到,元素"ab"和"ac"的长度是相等的,如果使用sort()排序的话二者的排序顺序不定,如果使用stable_sort的话会使用二者原来的位置来对二者进行存放。
unique()算法可以“去除”容器中相邻元素的重复元素,所以我们一般先将容器排好序再使用unique()。因为STL算法不能直接添加或删除元素,所以unique()“去除”重复元素后容器大小不变,并返回最后一个元素之后的迭代器,这个迭代器到end()之间的元素的值是不确定的,所以一般再使用容器的成员函数erase()来删除这些无用的元素。

2、count()、count_if()

 count()用来计算容器中与指定值相等的元素的个数,count_if()算法用来计算容器中符合指定条件元素的个数。 

 计算一个容器中元素长度小于5的元素个数,使用函数指针跟函数对象的话代码是这样子:

bool ShorterThanFun(const string& str){return str.length() < 5;}int count = count_if(myVector.begin(), myVector.end(), ShorterThanFun);class ShorterThan{public:bool operator() (const string& str) const{return str.length() < 5;}};int count = count_if(myVector.begin(), myVector.end(), ShorterThan());

  如果我们要选取的元素的长度不是小于固定值5而是小于一个变量的话那么则只有使用函数对象能够完成,因为算法所使用的仿函数是固定参数的,而函数对象则可以通过它的构造函数来传入额外的参数,如下所示:

class ShorterThan {public:explicit ShorterThan(int maxLength) : length(maxLength) {}bool operator() (const string& str) const {return str.length() < length;}private:const size_t length;};int count = count_if(myVector.begin(), myVector.end(), ShorterThan(length));

简而言之,使用函数对象相比函数来说提供了更多的操作和功能,比如可以传入参数给函数对象的构造函数,以供给函数对象中的operator()函数使用。

其实,使用bind的话会比上面的编码更方便,详见:http://www.cnblogs.com/milanleon/p/7491180.html。

3、find()、find_if()

find()算法用来查找与指定值相等的元素,它找到第一个相等的元素就返回其迭代器。

find_if()是find()的增强版本,它可以查找容器中符合指定条件的元素,其第三个参数就是一个函数或函数对象。

如下为查找容器中的第一个偶数元素,分别使用函数指针和函数对象:

#include <vector>#include <algorithm> bool IsEven(int i){return ((i & 1) == 0);}class FindIf{public:bool operator()(const int& i){return ((i & 1) == 0);}};int main(){std::vector<int> myvector;myvector.push_back(15);myvector.push_back(25);myvector.push_back(30);myvector.push_back(60);auto it = std::find_if(myvector.begin(), myvector.end(), FindIf()/*IsEven*/);if(it != myvector.end())std::cout << "The first even value is " << *it << '\n';return 0;}

4、remove()、remove_if()

remove()用来"移除"与指定值相等的元素, 因为STL算法不能直接添加或删除元素,所以remove()其实并不删除元素只是将相等的元素移动到容器末尾,并返回指向末尾第一个移除元素的迭代器。所以一般我们是在remove()以后获得指向末尾第一个删除的元素的迭代器iter,然后再调用erase来真正删除这些元素:                  vc.erase(iter, vc.end());

remove_if()是remove()的增强版,它能够移除符合指定条件的元素,它实际上是将所有应该移除的元素都移动到了容器尾部并返回一个分界的迭代器,所以还应该调用

vector::erase(const_iterator first, const_iterator last)来删除这些区间中元素。remove_if()不能用于管理容器map或set。
eg:移除vector中大于10的元素:
#include <vector>#include <algorithm>bool GreaterThan(int& i){return i > 10;}class CGreater{public:bool operator()(int& i){return i > 10;}};int main(){int a[] = { 1, 3, 12, 15};vector< int> arr(a, a + 4);arr.erase(remove_if(arr.begin(), arr.end(), CGreater()/*GreaterThan*/), arr.end());for (auto iter = arr.begin(); iter != arr.end(); iter++)cout << *iter << endl;return 0;}

5、for_each()

for_each()对容器中的每个元素执行指定的操作,如下为使用示例,分别使用函数指针和函数对象:

#include <vector>#include <algorithm> #include "boost/assign.hpp"using namespace boost::assign;void SquareFun(int& x){x = x * x;}class Square{public:void operator()(int& x){x = x * x;}};int main(){vector<int> v = list_of(1) (2) (3) (4);for_each(v.begin(), v.end(), Square()/*SquareFun*/);auto iter = v.begin(), iterEnd = v.end();for (; iter != iterEnd; iter++)cout << *iter << endl;return 0;}


转载及参考出处:http://www.cnblogs.com/decade-dnbc66/p/5347088.html


原创粉丝点击