函数对象(function objects),之前叫做仿函数(functor)。顾名思义,就是函数产生的对象。从语言层面上来讲,它是一个类对象,实际上,我们把它当成一个函数来用。
先举个栗子(我也皮一下:D):
/*code block 1*/
#include <iostream>
using namespace std;
/*这里定义了一个类IsEqual并重载了其operator()函数,实际上这个类也只有这个函数*/
struct IsEqual {
template <class T>
bool operator()(const T& lhs, const T& rhs) {
return lhs == rhs;
}
};
int main() {
IsEqual isEqual;
cout << boolalpha << isEqual(3, 5) << endl;
cout << isEqual(5, 5) << endl;
cout << isEqual('c', 'c') << endl;
return 0;
}
/*
输出为:
false
true
true
*/
当然,它不仅仅只能满足基础类型的相等比较,类类型也是可以的,但是需要被比较的类型重载operator==()函数,这里只是举个例子。
下面就给出类类型比较的例子:
/*code block 2*/
#include <iostream>
using namespace std;
struct IsEqual {
template <class T>
bool operator()(const T& lhs, const T& rhs) {
return lhs == rhs;
}
};
class People {
public:
/*这里重载了双目operator==()运算符*/
friend bool operator==(const People& lhs, const People& rhs) {
return lhs.id == rhs.id;
}
People(string _id) : id(_id) {
}
private:
string id;
};
int main() {
IsEqual isEqual;
People a("0123");
People b("1234");
People c("0123");
/*以下两种方法都是可以的*/
cout << boolalpha << isEqual(a, b) << endl;
cout << isEqual(a, c) << endl;
cout << IsEqual()(a, b) << endl;
cout << IsEqual()(a, c) << endl;
return 0;
}
/*
输出为:
false
true
false
true
*/
(排版怎么乱了,很奇怪)
代码块2中给出了类类型也可以参与使用函数对象进行值的比较。isEqual是IsEqual的一个对象,而IsEqual()是一个临时对象,这两种方法都是可以的。
其实函数对象大多数时候不是这么定义的,而是按照如下的方式:
/*code block 3*/
#include <iostream>
using namespace std;
template <class T>
struct IsEqual {
bool operator()(const T& lhs, const T& rhs) {
return lhs == rhs;
}
};
int main() {
int i1 = 5;
int i2 = 6;
char ch1 = 'A';
char ch2 = 'M';
string str1 = "string";
string str2 = "string";
cout << boolalpha;
cout << IsEqual<int>()(i1, i2) << endl;
cout << IsEqual<char>()(ch1, ch2) << endl;
cout << IsEqual<string>()(str1, str2) << endl;
return 0;
}
/*
输出为:
false
false
true
*/
使用代码块3的方式,定义模板类而不仅是普通类的模板成员函数,在使用时可以更加直观的了解参与比较的对象的类型。
看到这里,有人就说了,这样有什么用吗,有点多此一举,明明可以直接比较,非要搞这些有的没的。
确实,如果函数对象的作用只是这么点,确实也没有存在的必要了。
其实,函数对象的主要作用是为了搭配STL算法使用。(《STL源码剖析》)
下面贴几张图:
也不给出太多的图了,sort()可以说是很经典的一个函数了。再它的custom版本中,需要给出三个参数,第三个参数是comp(我把它叫做比较器),如果该参数缺省,那就是默认采用升序排列。我们可以自己编写一个比较器(实质是一个函数对象),实现其他形式的排序。
/*code block 4*/
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
template <class T>
struct Greater {
bool operator()(const T& lhs, const T& rhs) {
return lhs > rhs;
}
};
int main() {
vector<int> ve = {1, 7, 8, 3, 2, 4, 6};
for(auto &e : ve) {
cout << e << " ";
}
cout << endl;
sort(ve.begin(), ve.end());
for(auto &e : ve) {
cout << e << " ";
}
cout << endl;
/*调用自己实现的Greater*/比较器
sort(ve.begin(), ve.end(), Greater<int>());
for(auto &e : ve) {
cout << e << " ";
}
cout << endl;
return 0;
}
/*
输出为:
1 7 8 3 2 4 6
1 2 3 4 6 7 8
8 7 6 4 3 2 1
*/
上面的count_if()函数,功能是计算满足某个区间内所有满足某种条件的元素的个数。这个条件需要我们自己制定,这时候函数对象就要出马了。但是,我们发现对于不同的情况,这个条件千差万别,怎么办?
这个时候,我觉得lambda函数可以出来亮个相。
/*code block 5*/
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
int main() {
vector<double> ve = {1.01, 2.9999, 3.000001, 3.0, 3.002, 2.999, 4, 3.5, 2.998};
cout << ve.size() << endl;
cout << count_if(ve.begin(), ve.end(), [](double d) {
return fabs(d - 3.0) < 0.01;
}) << endl;
return 0;
}
/*
输出为:
9
6
*/
上面的count_if()函数实现的功能是统计ve中在(2.99,3.01)中的元素个数。
关于lambda函数,以后再来详述。
在<functional>头文件中提供了许多函数对象的原型(或者这里叫“仿函数”更合适)。许多我们可以直接拿来用,但是实现起来都不难,有兴趣可以自己实现。
所有函数声明都可以在http://www.cplusplus.com/reference/functional/中找到。