仿函数通过重载operator()实现可调用对象,核心优势是能携带状态(如成员变量),而普通函数无法保存上下文;它支持多参数重载、编译期内联,并天然适配STL模板机制。

为什么重载 operator() 而不是写普通函数
因为仿函数(functor)需要携带状态,而普通函数无法直接保存上下文。比如你写一个累加器,每次调用都基于上次的值递增——这必须靠对象成员变量存状态,operator() 就是让这个对象“看起来像函数”被调用的入口。
关键点:重载 operator() 后,类实例可像函数一样使用括号调用,但它是有状态、可拷贝、可传参的完整对象。
operator() 的声明和参数灵活性
它本质是个成员函数,可以重载多次(即函数重载),支持任意参数列表和返回类型,只要不带 const 限定符就默认能修改对象状态。
- 常见写法:
int operator()(int x) { return value += x; } - 支持 const 版本:
int operator()() const { return value; }(只读访问) - 支持多参数:
double operator()(double a, double b) const { return a * scale + b; } - 不能是静态函数,也不能是虚函数(除非你明确需要多态仿函数,那得配合基类+指针/引用)
在 STL 算法里怎么安全传入仿函数
STL(如 std::sort、std::transform)内部会拷贝传入的仿函数对象。如果仿函数含指针或独占资源(比如 std::unique_ptr),默认拷贝可能出问题。
立即学习“C++免费学习笔记(深入)”;
- 若需共享状态,用
std::ref(my_functor)传引用(C++11 起) - 若含非拷贝成员,显式删除拷贝构造/赋值:
MyFunctor(const MyFunctor&) = delete; - 更稳妥的做法是把状态抽到外部,仿函数只负责逻辑;或改用 lambda(捕获引用/指针)
- 注意:lambda 本质也是编译器生成的仿函数类,只是语法糖
容易忽略的 const 正确性和移动语义
很多初学者只写一个非 const 版 operator(),结果在 const 上下文中(比如 const 对象调用、或被 const 引用传入 STL)编译失败,报错类似 no match for call to ‘const Counter::operator()()’。
- 按需提供 const 版本,尤其是只读操作时
- 若仿函数内部修改了 mutable 成员,可在 const 函数中调用:
mutable int cache; - C++11 后,如果仿函数含大对象(如
std::vector),考虑为operator()提供右值引用重载,避免不必要的拷贝
真正麻烦的不是写出来,而是忘了 const 与非 const 的配对,以及在泛型代码里被意外拷贝后状态丢失——这两点比语法本身更容易导致线上行为异常。


















