operator() 在 C++ 中被称为 函数调用运算符 ,它允许类的对象像函数一样被调用。这种对象被称为 函数对象 或 仿函数。
一、基本语法
cpp
class MyFunctor {
public:
// 重载 () 运算符
return_type operator()(parameters) {
// 实现代码
}
};
// 使用
MyFunctor functor;
functor(arg1, arg2); // 像函数一样调用
二、基础示例
示例 1:简单的仿函数
cpp
#include <iostream>
class Adder {
private:
int value;
public:
Adder(int v) : value(v) {}
// 重载 () 运算符
int operator()(int x) {
return value + x;
}
};
int main() {
Adder add5(5);
Adder add10(10);
std::cout << add5(3) << std::endl; // 输出: 8
std::cout << add5(10) << std::endl; // 输出: 15
std::cout << add10(3) << std::endl; // 输出: 13
return 0;
}

示例 2:带状态的计数器
cpp
#include <iostream>
class Counter {
private:
int count;
public:
Counter() : count(0) {}
int operator()() {
return ++count;
}
int operator()(int increment) {
count += increment;
return count;
}
void reset() { count = 0; }
};
int main() {
Counter counter;
std::cout << counter() << std::endl; // 输出: 1
std::cout << counter() << std::endl; // 输出: 2
std::cout << counter(5) << std::endl; // 输出: 7
counter.reset();
std::cout << counter() << std::endl; // 输出: 1
return 0;
}
三、在 STL 算法中的应用
operator() 在 STL 中非常有用,特别是与算法配合使用:
示例 3:自定义比较器
cpp
#include <iostream>
#include <vector>
#include <algorithm>
class CompareByLength {
public:
bool operator()(const std::string& a, const std::string& b) const {
return a.length() < b.length();
}
};
class GreaterThan {
private:
int threshold;
public:
GreaterThan(int t) : threshold(t) {}
bool operator()(int x) const {
return x > threshold;
}
};
int main() {
// 1. 使用自定义比较器排序
std::vector<std::string> words = {"apple", "banana", "cherry", "date"};
std::sort(words.begin(), words.end(), CompareByLength());
for (const auto& word : words) {
std::cout << word << " "; // 输出: date apple cherry banana
}
std::cout << std::endl;
// 2. 使用自定义谓词
std::vector<int> numbers = {1, 5, 10, 15, 20, 25};
GreaterThan gt10(10);
// 使用 find_if
auto it = std::find_if(numbers.begin(), numbers.end(), gt10);
if (it != numbers.end()) {
std::cout << "First number > 10: " << *it << std::endl; // 输出: 15
}
// 统计大于10的元素个数
int count = std::count_if(numbers.begin(), numbers.end(), GreaterThan(10));
std::cout << "Count > 10: " << count << std::endl; // 输出: 3
return 0;
}
四、Lambda 表达式与仿函数的关系
Lambda 表达式本质上是创建了一个匿名的仿函数类:
cpp
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};
// Lambda 表达式
auto lambda = [](int x) { return x * 2; };
// 这等价于下面的仿函数
class LambdaEquivalent {
public:
int operator()(int x) const {
return x * 2;
}
};
// 使用 lambda
std::transform(numbers.begin(), numbers.end(), numbers.begin(), lambda);
for (int n : numbers) {
std::cout << n << " "; // 输出: 2 4 6 8 10
}
std::cout << std::endl;
return 0;
}
五、带捕获的 Lambda 对应的仿函数
cpp
#include <iostream>
int main() {
int factor = 3;
// Lambda 表达式捕获外部变量
auto lambda = [factor](int x) { return x * factor; };
// 对应的仿函数实现
class LambdaWithCapture {
private:
int factor; // 捕获的变量作为成员
public:
LambdaWithCapture(int f) : factor(f) {}
int operator()(int x) const {
return x * factor;
}
};
std::cout << lambda(5) << std::endl; // 输出: 15
LambdaWithCapture functor(factor);
std::cout << functor(5) << std::endl; // 输出: 15
return 0;
}
六、高级应用示例
示例 4:函数适配器
cpp
#include <iostream>
#include <functional>
// 自定义函数适配器:将二元函数转换为一元函数
template<typename Func, typename SecondArg>
class BindSecond {
private:
Func func;
SecondArg second;
public:
BindSecond(Func f, SecondArg s) : func(f), second(s) {}
template<typename FirstArg>
auto operator()(FirstArg&& first) {
return func(std::forward<FirstArg>(first), second);
}
};
int multiply(int a, int b) {
return a * b;
}
int main() {
// 使用标准库的 bind
using namespace std::placeholders;
auto multiplyBy5 = std::bind(multiply, _1, 5);
// 使用自定义的适配器
BindSecond<decltype(&multiply), int> multiplyBy3(multiply, 3);
std::cout << multiplyBy5(10) << std::endl; // 输出: 50
std::cout << multiplyBy3(10) << std::endl; // 输出: 30
return 0;
}
示例 5:记忆化(Memoization)
cpp
#include <iostream>
#include <unordered_map>
#include <functional>
class Memoizer {
private:
std::function<int(int)> func;
std::unordered_map<int, int> cache;
public:
Memoizer(std::function<int(int)> f) : func(f) {}
int operator()(int n) {
if (cache.find(n) != cache.end()) {
std::cout << "Cache hit for " << n << std::endl;
return cache[n];
}
std::cout << "Computing for " << n << std::endl;
int result = func(n);
cache[n] = result;
return result;
}
};
int expensiveComputation(int n) {
// 模拟耗时计算
return n * n;
}
int main() {
Memoizer memo(expensiveComputation);
std::cout << memo(5) << std::endl; // 计算并缓存
std::cout << memo(5) << std::endl; // 从缓存读取
std::cout << memo(10) << std::endl; // 计算并缓存
std::cout << memo(10) << std::endl; // 从缓存读取
return 0;
}
示例 6:访问者模式中的应用
cpp
#include <iostream>
#include <vector>
class Circle;
class Square;
// 访问者基类
class ShapeVisitor {
public:
virtual void operator()(Circle& circle) = 0;
virtual void operator()(Square& square) = 0;
};
// 形状基类
class Shape {
public:
virtual void accept(ShapeVisitor& visitor) = 0;
virtual ~Shape() = default;
};
// 具体形状
class Circle : public Shape {
public:
double radius;
Circle(double r) : radius(r) {}
void accept(ShapeVisitor& visitor) override {
visitor(*this);
}
};
class Square : public Shape {
public:
double side;
Square(double s) : side(s) {}
void accept(ShapeVisitor& visitor) override {
visitor(*this);
}
};
// 具体访问者:面积计算器
class AreaCalculator : public ShapeVisitor {
public:
double totalArea = 0;
void operator()(Circle& circle) override {
double area = 3.14159 * circle.radius * circle.radius;
std::cout << "Circle area: " << area << std::endl;
totalArea += area;
}
void operator()(Square& square) override {
double area = square.side * square.side;
std::cout << "Square area: " << area << std::endl;
totalArea += area;
}
};
int main() {
std::vector<Shape*> shapes = {
new Circle(5.0),
new Square(4.0),
new Circle(3.0)
};
AreaCalculator calculator;
for (auto shape : shapes) {
shape->accept(calculator);
}
std::cout << "Total area: " << calculator.totalArea << std::endl;
// 清理
for (auto shape : shapes) {
delete shape;
}
return 0;
}
七、operator() 的优点
-
可维护状态 与普通函数不同,仿函数可以有成员变量,可以保存状态
-
可内联 编译器更容易内联
operator()的调用,性能更好 -
可模板化 仿函数可以是模板类,提供更大的灵活性
-
STL兼容 STL算法通常要求函数对象,使用
operator()可以无缝集成 -
多态性 可以通过继承和虚函数实现多态行为
八、使用建议
-
对于简单的、一次性使用的函数对象,优先使用 Lambda
-
当需要复杂的状态管理、继承或多态时,使用显式的仿函数类
-
如果
operator()不修改对象状态,声明为const成员函数 -
在模板化的
operator()中使用完美转发
cpp
class GenericFunctor {
public:
template<typename T, typename U>
auto operator()(T&& t, U&& u) const {
return std::forward<T>(t) + std::forward<U>(u);
}
};
operator() 是 C++ 中实现函数对象的核心机制,它提供了比普通函数指针更强大、更灵活的功能,是现代 C++ 编程中的重要工具。