在 C++ 中,函数对象(Function Object)是一种可调用对象,它允许像函数一样被调用,但实际上它可能并不是真正的函数。函数对象可以是以下几种类型之一:
- 普通函数:
- 一个普通的、定义在命名空间或类中的函数。
- 函数指针:
- 一个指向函数的指针,可以像函数一样被调用。
- 函数对象(也称为仿函数,Functor):
- 一个重载了 operator() 的类对象或结构体对象。
- C++11 引入的 Lambda 表达式:
- 一个匿名的函数对象,通过 [capture](parameters) mutable -> return_type { body } 语法定义。
- 标准库中的函数对象(也称为函数适配器):
- 如 std::ptr_fun、std::mem_fun、std::negate、std::plus 等,这些通常是模板类或函数模板,用于适配或生成函数对象。
特点
- 重载
operator():
- 对于自定义的函数对象,必须重载 operator() 以使对象具备可调用性。
cpp
struct MyFunctor {
void operator()(int x) const {
std::cout << "Called with " << x << std::endl;
}
};
int main() {
MyFunctor f;
f(10); // 输出: Called with 10
return 0;
}
2.灵活性
- 函数对象可以携带状态,因为它们是对象。这意味着它们的行为可以依赖于对象的状态。
cpp
struct Counter {
int count = 0;
void operator()() {
++count;
std::cout << "Count: " << count << std::endl;
}
};
int main() {
Counter counter;
counter(); // 输出: Count: 1
counter(); // 输出: Count: 2
return 0;
}
3.类型安全:
- 函数对象可以像类一样进行类型检查,提供更强的类型安全性。
4.可重用性
- 通过传递函数对象作为参数,可以提高代码的重用性和模块化。
5.与标准库结合良好
- C++ 标准库中的很多算法(如 std::sort、std::for_each 等)都接受函数对象作为参数,使得它们更加灵活和强大。
示例:使用函数对象与标准库算法
cpp
#include <iostream>
#include <vector>
#include <algorithm>
struct Print {
void operator()(int x) const {
std::cout << x << " ";
}
};
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
// 使用函数对象 Print 作为 std::for_each 的参数
std::for_each(vec.begin(), vec.end(), Print());
std::cout << std::endl;
return 0;
}
输出:
cpp
输出:1 2 3 4 5
在这个例子中,Print 是一个函数对象,通过重载 operator(),它能够在 std::for_each 中被调用,从而遍历并打印 std::vector 中的每个元素。
函数对象是 C++ 中一个强大的特性,它提供了灵活且类型安全的方式来封装和传递可调用行为。