0%

C++仿函数

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;
}