题目

编写程序,演示函数调用运算符 operator() 重载所打造的仿函数(Functor / Function Object)。展示仿函数相对于普通 C 语言裸函数指针的优势:能够携带自身内部状态(如累计调用次数)。手写带内部统计的倍乘仿函数 StatefulMultiplier,并将其分别交给 STL 算法 std::transform 与 std::for_each。

输入格式:无需外部输入。

输出格式:输出仿函数多次调用时的状态持久性演变与在 STL 算法中的应用结果。

数据范围与约定:仿函数、有状态闭包与内联优化优势。

思路与算法

1. 仿函数比函数指针快的原因
普通函数指针是一个动态运行时间接寻址,编译器几乎无法对其进行跨文件内联优化;而仿函数是一个具体的类型(Type),当模板算法接收仿函数时,编译器能够彻底将其 operator() 展开为极致的零开销内联汇编!

2. 状态保存能力
普通函数必须借助危险的全局变量才能保存状态;而仿函数作为一个完备的类实例,可以在其私有成员中随意持久化保存历史运行状态。

3. 多重重载能力
同一个仿函数类可以对 operator() 依据参数个数和类型重载多个不同的签名,灵活性极强。

完整程序

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>

// 带内部状态的仿函数
class StatefulMultiplier {
private:
    int factor_;
    int callCount_;

public:
    explicit StatefulMultiplier(int factor) : factor_(factor), callCount_(0) {}

    // 重载函数调用运算符 operator()
    int operator()(int x) {
        ++callCount_;
        return x * factor_;
    }

    int getCallCount() const { return callCount_; }
    int getFactor() const { return factor_; }
};

int main() {
    // 1. 独立仿函数调用:表现得就像一个真正的函数,同时记录状态
    StatefulMultiplier times3(3);
    std::cout << "--- 1. 仿函数独立调用 ---\n";
    std::cout << "times3(10) = " << times3(10) << "\n";
    std::cout << "times3(25) = " << times3(25) << "\n";
    std::cout << "该仿函数已累计被调用: " << times3.getCallCount() << " 次\n\n";

    // 2. 将仿函数注入 STL 标准算法 std::transform
    std::vector<int> nums = {1, 2, 3, 4, 5};
    std::vector<int> results(nums.size());

    // 传入倍乘 10 的仿函数
    StatefulMultiplier times10(10);
    std::transform(nums.begin(), nums.end(), results.begin(), std::ref(times10));

    std::cout << "--- 2. std::transform 结合仿函数运行结果 ---\n";
    std::cout << "变换后结果: ";
    for (int x : results) std::cout << x << " ";
    std::cout << "\n算法执行后仿函数内部计数: " << times10.getCallCount() << " 次\n";

    StatefulMultiplier times2(2);
    std::for_each(nums.begin(), nums.end(), std::ref(times2));
    std::cout << "\n--- 3. std::for_each 结合仿函数 ---\n";
    std::cout << "for_each 遍历调用次数: " << times2.getCallCount() << " 次\n";

    return 0;
}

运行示例

输出:

--- 1. 仿函数独立调用 ---
times3(10) = 30
times3(25) = 75
该仿函数已累计被调用: 2 次

--- 2. std::transform 结合仿函数运行结果 ---
变换后结果: 10 20 30 40 50 
算法执行后仿函数内部计数: 5 次

--- 3. std::for_each 结合仿函数 ---
for_each 遍历调用次数: 5 次