在 C++ 中,仿函数(Functor) 是指重载了 operator() 的类或结构体的对象,它们的行为类似于普通函数,因此可以像函数一样被调用。仿函数在 STL 算法、回调机制、函数适配器等场景中有着广泛的应用。本文将深入探讨仿函数的概念、优点、使用方式,并结合具体示例进行详细解析。
在 C++ 中,我们可以用普通函数或 std::function(C++11 引入)来定义可调用对象,但仿函数相比之下有以下优势:
std::sort() 可接受仿函数作为自定义排序规则。要定义一个仿函数,需要在类或结构体中重载 operator(),示例如下:
#include <iostream>
// 定义仿函数类
struct Add {
int operator()(int a, int b) {
return a + b;
}
};
int main() {
Add add; // 创建仿函数对象
std::cout << "3 + 5 = " << add(3, 5) << std::endl; // 像函数一样调用
return 0;
}operator() 使 Add 对象 add 变成可调用对象,类似于普通函数 add(3, 5)。operator() 可以接受参数,并返回计算结果。仿函数可以存储状态,使其在多个调用间保持数据。例如,创建一个计算调用次数的仿函数:
#include <iostream>
class Counter {
private:
int count;
public:
Counter() : count(0) {} // 初始化计数器为 0
int operator()(int value) {
count++;
return count * value; // 使用 count 影响计算结果
}
int getCount() const { return count; }
};
int main() {
Counter counter;
std::cout << counter(10) << std::endl; // 第 1 次调用
std::cout << counter(10) << std::endl; // 第 2 次调用
std::cout << "调用次数:" << counter.getCount() << std::endl;
return 0;
}count 作为成员变量存储状态,每次调用 operator() 都会递增 count。STL 算法通常需要比较、变换、筛选等规则,这时候自定义仿函数特别有用。例如,自定义排序规则:
#include <iostream>
#include <vector>
#include <algorithm>
// 自定义比较规则(降序)
struct Compare {
bool operator()(int a, int b) {
return a > b; // 降序排序
}
};
int main() {
std::vector<int> vec = {5, 2, 8, 1, 3};
std::sort(vec.begin(), vec.end(), Compare()); // 传递仿函数对象
for (int num : vec) {
std::cout << num << " ";
}
return 0;
}std::sort() 默认是升序排序,我们自定义 Compare 作为降序比较规则。std::sort(vec.begin(), vec.end(), Compare()); 传递了 Compare 类型的临时对象作为排序准则。C++ STL 提供了一些标准仿函数,主要在 <functional> 头文件中,例如:
std::plus<T>、std::minus<T>、std::multiplies<T>、std::divides<T> 等。std::greater<T>、std::less<T>、std::equal_to<T> 等。std::logical_and<T>、std::logical_or<T> 等。示例:使用 std::greater<> 进行降序排序:
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional> // 包含标准仿函数
int main() {
std::vector<int> vec = {5, 2, 8, 1, 3};
std::sort(vec.begin(), vec.end(), std::greater<int>()); // 使用标准仿函数降序排序
for (int num : vec) {
std::cout << num << " ";
}
return 0;
}std::greater<int>() 作为 std::sort 的比较函数,与我们自己写的 Compare 作用类似。C++11 引入了 Lambda 表达式,使得代码更加简洁,许多仿函数的使用场景可以用 Lambda 代替。例如:
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> vec = {5, 2, 8, 1, 3};
// 使用 Lambda 进行降序排序
std::sort(vec.begin(), vec.end(), [](int a, int b) { return a > b; });
for (int num : vec) {
std::cout << num << " ";
}
return 0;
}struct 作为仿函数类。std::sort() 处定义逻辑,代码更直观。尽管 Lambda 更简洁,但仿函数在需要存储状态、复用代码、跨多个地方使用时仍然是很好的选择。
特性 | 普通函数 | Lambda | 仿函数 |
|---|---|---|---|
是否可存储状态 | ❌ 否 | ⚠️ 仅限闭包捕获 | ✅ 是 |
是否可复用 | ✅ 是 | ❌ 否(仅局部作用域) | ✅ 是 |
性能优化 | ⚠️ 可能无法内联 | ✅ 内联优化 | ✅ 内联优化 |
适用场景 | 一般计算 | 简单的一次性逻辑 | STL、回调、复杂逻辑 |
std::sort())。仿函数是 C++ 语言中的重要概念,它使得对象可以像函数一样调用,并在 STL 算法、回调、状态存储等场景中发挥重要作用。虽然 C++11 引入的 Lambda 使代码更加简洁,但仿函数在某些特定场景(如 STL 和状态保持)下仍然不可替代。
如果你对 C++ STL、Lambda 或智能指针等话题感兴趣,可以查看相关的深入文章! 🚀