在 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() 以使对象具备可调用性。
struct MyFunctor {void operator()(int x) const {std::cout << "Called with " << x << std::endl;}
};
int main() {MyFunctor f;f(10); // 输出: Called with 10return 0;
}
灵活性:函数对象可以携带状态,因为它们是对象。这意味着它们的行为可以依赖于对象的状态。
struct Counter {int count = 0;void operator()() {++count;std::cout << "Count: " << count << std::endl;}
};
int main() {Counter counter;counter(); // 输出: Count: 1counter(); // 输出: Count: 2return 0;
}
类型安全:函数对象可以像类一样进行类型检查,提供更强的类型安全性。
可重用性:通过传递函数对象作为参数,可以提高代码的重用性和模块化。
与标准库结合良好:C++ 标准库中的很多算法(如 std::sort、std::for_each 等)都接受函数对象作为参数,使得它们更加灵活和强大。
示例:使用函数对象与标准库算法
#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;
}//输出:1 2 3 4 5
在这个例子中,Print 是一个函数对象,通过重载 operator(),它能够在 std::for_each 中被调用,从而遍历并打印 std::vector 中的每个元素。
函数对象是 C++ 中一个强大的特性,它提供了灵活且类型安全的方式来封装和传递可调用行为。