C++仿函数

本文最后更新于:2022年10月18日 下午

仿函数是重载了()运算符的类

类可以重载函数调用运算符(),使其对象的行为像函数一样,这样的类的对象被称作函数对象

为什么要使用仿函数

在保持函数参数的前提下,使函数带有状态和调节参数

在使用泛型算法时,通常需要传入一个函数作为比较条件、要执行的操作…,而且函数调用者往往规定了传入函数的形参,你无法调整传入函数的执行参数。

如下,打印一个数组的每个元素:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void PrintNumber(int n) {
cout << n;
}

void PrintArray(int arr[], int size, function<void(int)> Print) {
for (int i = 0; i < size; ++i) {
Print(arr[i]);
}
}

int main() {
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
PrintArray(arr, 10, PrintNumber);
}

输出:

1
12345678910

数字连到一起了,我们希望在输出数字之后跟一个空格,如果直接更改输出函数,那就需要针对每个要求写一种输出函数。通过传参看似可以解决。

1
2
3
void PrintNumber(int n, char end[]) {
cout << n << end;
}

但是无法满足PrintArray要求的形参。

一种可行的思路是使用全局变量,但是这不符合规范,不优雅,使用也不方便容易出错。

使用类则解决了这个问题,类的成员变量对于成员函数就好像全部变量一般,而且方便管理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class PrintNumber {
public:
explicit PrintNumber(string end) : _end(end) {}
void operator()(int n) {
cout << n << _end;
}
private:
string _end;
};

void PrintArray(int arr[], int size, function<void(int)> Print) {
for (int i = 0; i < size; ++i) {
Print(arr[i]);
}
}

int main() {
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
PrintArray(arr, 10, PrintNumber(" "));
}

输出:

1
1 2 3 4 5 6 7 8 9 10

仿函数在标准库中大量使用,优点在于

  • 逻辑分离,将迭代与计算、比较等逻辑解耦
  • 参数可设置
  • 有状态
  • 性能更好

标准库 function 类型

为了解决函数指针、函数对象、lambda 表达式类型不同的问题,C++11 引入了function类型。

function是一个模板,使用时只需要把形参返回值传入即可。

形如:function<返回类型(形参类型,形参类型...)> 对象名称

可以用函数指针、函数对象类的对象、lambda 表达式直接为其赋值。


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