STL专题-函数对象

本文最后更新于:2021年2月7日 下午

STL函数对象,即仿函数。

函数对象

  • 重载函数调用操作符的类,其对象常称为函数对象
  • 函数对象使用重载的()时,行为类似函数调用,也叫仿函数

函数对象本质上是一个类的对象,然后重载了(),看起来像一个函数调用,但实际上是一个类。

函数对象的使用

  1. 函数对象使用时可以像普通函数那样调用,可以有参数,可以由返回值,均可以通过重载()来实现。
  2. 函数对象不同于普通函数,因为其本质是一个类,通过类,函数对象可以拥有自身的状态,但是普通函数需要全局变量或者静态变量。
  3. 函数对象可以通过参数传递。
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
32
33
34
35
36
37
38
class MyAdd {
public:

MyAdd() {
count = 0;
}
int operator()(int a,int b){
count++;
return a + b;
}

int operator()(int a, int b, int c) {
count++;
return a + b + c;
}

int count;
};

int myFunc(MyAdd& myadd, int a, int b) {
return myadd(a, b);
}

void test1() {

//函数对象的使用

MyAdd myadd;

cout << myadd(1, 2) << endl;
cout << myadd(1, 2, 3) << endl;
cout << myadd(1, 2, -3) << endl;

cout << myFunc(myadd, 2, -3) << endl;

cout << myadd.count << endl;

}

谓词

  • 返回bool类型的仿函数称为谓词
  • 如果operator()接受一个参数,那么叫做一元谓词
  • 如果operator()接受两个参数,那么叫做二元谓词
  • 谓词在STL算法的调用中使用非常广泛,通过自定义谓词,可以使得STL算法适用于自定义数据类型,并且写法非常灵活。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Greater30 {
public:
bool operator()(int val) {
return val > 30;
}
};

void test2() {

int num = 50;

//匿名对象的方式调用
if (Greater30()(num)) {
cout << "num : "<<num<<" 大于30" << endl;
}else
cout << "num : " << num << " 小于30" << endl;

}

STL内建函数对象

使用内建函数对象,需要引入头文件 #include<functional>

这些仿函数所产生的对象,用法和一般函数完全相同。

算数仿函数

  • template<class T> T plus<T> //加法仿函数

  • template<class T> T minus<T> //减法仿函数

  • template<class T> T multiplies<T> //乘法仿函数

  • template<class T> T divides<T> //除法仿函数

  • template<class T> T modulus<T> //取模仿函数

  • template<class T> T negate<T> //取反仿函数

  • 其中negate是一元运算,其他都是二元运算

1
2
3
4
5
6
7
8
9
10
void test3() {

negate<int> neg;
cout << neg(12) << endl;

plus<int> add;

cout << add(1, 23) << endl;

}

关系仿函数

  • template<class T> bool equal_to<T> //等于
  • template<class T> bool not_equal_to<T> //不等于
  • template<class T> bool greater<T> //大于
  • template<class T> bool greater_equal<T> //大于等于
  • template<class T> bool less<T> //小于
  • template<class T> bool less_equal<T> //小于等于

比较常用的是大于仿函数。

sort默认排序适用的是less仿函数,更改排序方式时,可以适用greater仿函数,不需要自己再实现。

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
32
33
34
35
36
37
38
39
40
41
class MyCmp {
public:
bool operator()(int a, int b) {
return a > b;
}
};

void PrintVector(vector<int> &v) {
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
cout << *it << " ";
cout << endl;
}

void test4() {

vector<int> v;
v.push_back(1);
v.push_back(5);
v.push_back(6);
v.push_back(3);
v.push_back(4);
v.push_back(2);

//从小到大排序,实质是调用了less仿函数
sort(v.begin(),v.end());
PrintVector(v);

//从大到小排序,自己实现仿函数
sort(v.begin(),v.end(),MyCmp());
PrintVector(v);

//从大到小排序,使用greater仿函数
sort(v.begin(),v.end(),greater<int>());
PrintVector(v);

//上述等价于
greater<int> g;
sort(v.begin(), v.end(), g);
PrintVector(v);

}
  • 值得注意的一点,MyCmp()以及greater<int>()均为匿名对象。
  • 实际上第三个参数等待的对象是一个谓词。

逻辑仿函数

  • template<class T> bool logical_and<T> //逻辑与
  • template<class T> bool logical_or<T> //逻辑或
  • template<class T> bool logical_not<T> //逻辑非

实际使用较少。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!