C++中的仿函数介绍
仿函数
常见场景
当需要将函数作为一个参数传递进另一个函数时,可以使用函数指针。例如下面的例子:
假设我们现在有一个数组,数组中存有任意数量的数字,我们希望能够统计出这个数组中大于 10 的数字的数量,你的代码很可能是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #include <iostream> using namespace std;
int RecallFunc(int *start, int *end, bool (*pf)(int)) { int count=0; for(int *i=start;i!=end+1;i++) { count = pf(*i) ? count+1 : count; } return count; }
bool IsGreaterThanTen(int num) { return num>10 ? true : false; }
int main() { int a[5] = {10,100,11,5,19}; int result = RecallFunc(a,a+4,IsGreaterThanTen); cout<<result<<endl; return 0; }
|
但是,如果此时希望将判定的阈值也作为一个变量传入,变为如下函数就不可行了
1 2 3 4
| bool IsGreaterThanThreshold(int num, int threshold) { return num>threshold ? true : false; }
|
虽然这个函数看起来比前面一个版本更具有一般性,但是它不能满足已经定义好的函数指针参数的要求,因为函数指针参数的类型是bool (*)(int)
,与函数bool IsGreaterThanThreshold(int num, int threshold)
的类型不相符。如果一定要完成这个任务,按照以往的经验,我们可以考虑如下可能途径:
(1)阈值作为函数的局部变量。局部变量不能在函数调用中传递,故不可行; (2)函数传参。这种方法我们已经讨论过了,多个参数不适用于已定义好的 RecallFunc() 函数。 (3)全局变量。我们可以将阈值设置成一个全局变量。这种方法虽然可行,但是不优雅,且非常容易引入 Bug,比如全局变量容易同名,造成命名空间污染。
那么有什么好的处理方法呢?仿函数应运而生。
用法
编程者要将某种“操作”当做算法的参数,一般有两种方法:
(1)一个办法就是先将该“操作”设计为一个函数,再将函数指针当做算法的一个参数。上面的实例就是该做法; (2)将该“操作”设计为一个仿函数(就语言层面而言是个 class),再以该仿函数产生一个对象,并以此对象作为算法的一个参数。
仿函数写法: 写一个简单类,除了维护类的基本成员函数外(struct
也可),只需要重载 operator() 运算符 。这样既可以免去对一些公共变量的维护,也可以使重复使用的代码独立出来,以便下次复用。
示例
1 2 3 4 5 6
| struct Mycmp { bool operator () (vector<int> &a, vector<int> &b) { return a[1] > b[1]; } };
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #include <iostream> using namespace std;
class IsGreaterThanThresholdFunctor { public: explicit IsGreaterThanThresholdFunctor(int t):threshold(t){} bool operator() (int num) const { return num > threshold ? true : false; } private: const int threshold; };
int RecallFunc(int *start, int *end, IsGreaterThanThresholdFunctor myFunctor) { int count = 0; for (int *i = start; i != end + 1; i++) { count = myFunctor(*i) ? count + 1 : count; } return count; }
int main() { int a[5] = {10,100,11,5,19}; int result = RecallFunc(a, a + 4, IsGreaterThanThresholdFunctor(10)); cout << result << endl; }
|