c++中函数调用运算符重载的实现

 更新时间:2026年02月03日 08:57:44   作者:挖矿大亨  
在 C++ 中,函数调用运算符的重载是一种特殊的运算符重载方式,允许自定义类的对象像函数一样被调用,本文就来详细的介绍一下c++中函数调用运算符重载的实现,感兴趣的可以了解一下

在 C++ 中,函数调用运算符 () 的重载是一种特殊的运算符重载方式,允许自定义类的对象像函数一样被调用(这类对象也被称为 “函数对象” 或 “仿函数”)。函数调用运算符重载是实现 STL 算法(如sort、for_each)自定义逻辑的核心手段,也是现代 C++ 中 lambda 表达式的底层实现基础。

一、核心规则

1、重载方式:只能作为类的成员函数重载(全局函数无法重载())。
2、返回值:无固定要求(可返回任意类型,如int、bool、自定义类型,也可void)。
3、参数列表:支持任意数量、任意类型的参数(可重载多个版本,区分参数类型 / 个数)。
4、const 修饰:若函数对象无需修改自身状态,建议加const(保证常量对象可调用)。
5、语义:调用对象(参数)等价于调用对象.operator()(参数)。

二、基础示例:简单仿函数

先实现一个最基础的函数调用运算符重载,让对象能像函数一样执行逻辑:

#include <iostream>
using namespace std;

// 定义一个可调用的类(仿函数)
class Add {
public:
    // 重载函数调用运算符:接收两个int,返回和
    int operator()(int a, int b) const {
        return a + b;
    }
};

int main() {
    // 创建函数对象
    Add add_obj;
    
    // 像调用函数一样调用对象(等价于 add_obj.operator()(3,5))
    int result = add_obj(3, 5);
    cout << "3 + 5 = " << result << endl; // 输出:3 + 5 = 8

    // 也可直接创建临时对象并调用
    cout << "10 + 20 = " << Add()(10, 20) << endl; // 输出:10 + 20 = 30

    return 0;
}

三、进阶示例:带状态的仿函数

函数对象的核心优势是可保存状态(成员变量),这是普通函数无法做到的。例如实现一个 “累加器”:

#include <iostream>
using namespace std;

class Accumulator {
private:
    int total = 0; // 保存累加状态
public:
    // 重载1:接收int,累加并返回当前总和
    int operator()(int num) {
        total += num;
        return total;
    }

    // 重载2:无参版本,返回当前总和
    int operator()() const {
        return total;
    }

    // 重置状态
    void reset() {
        total = 0;
    }
};

int main() {
    Accumulator acc;
    
    // 多次调用,累计状态
    acc(10);  // total = 10
    acc(20);  // total = 30
    acc(30);  // total = 60

    cout << "累计总和:" << acc() << endl; // 输出:60

    acc.reset();
    acc(5);
    cout << "重置后累计:" << acc() << endl; // 输出:5

    return 0;
}

四、实战场景:配合 STL 算法使用

函数调用运算符重载最常用的场景是为 STL 算法提供自定义逻辑(如排序、遍历、筛选)。

示例 1:自定义排序规则

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

// 按年龄降序排序的仿函数
class CompareAgeDesc {
public:
    // 假设元素是pair<姓名, 年龄>
    bool operator()(const pair<string, int>& a, const pair<string, int>& b) const {
        return a.second > b.second; // 降序:a的年龄 > b的年龄则a排在前面
    }
};

int main() {
    vector<pair<string, int>> students = {
        {"张三", 20}, {"李四", 25}, {"王五", 18}
    };

    // 使用仿函数作为排序规则
    sort(students.begin(), students.end(), CompareAgeDesc());

    // 输出排序结果
    for (const auto& s : students) {
        cout << s.first << ":" << s.second << "岁" << endl;
    }

    return 0;
}

示例 2:遍历容器并累加

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

// 累加容器中元素的仿函数
class SumInt {
private:
    int sum = 0;
public:
    // 重载():接收int,累加
    void operator()(int num) {
        sum += num;
    }

    // 获取累加结果
    int getSum() const {
        return sum;
    }
};

int main() {
    vector<int> nums = {1, 2, 3, 4, 5};

    // 用for_each遍历,传入仿函数
    SumInt sum_obj = for_each(nums.begin(), nums.end(), SumInt());

    cout << "数组总和:" << sum_obj.getSum() << endl; // 输出:15

    return 0;
}

五、关键注意事项

1、与普通函数的区别:

函数对象可保存状态(成员变量),普通函数只能通过全局 / 静态变量实现(不推荐);
函数对象支持重载(多个operator()版本,区分参数),普通函数重载需手动写多个函数名。

2、const 正确性:

若仿函数无需修改自身状态,务必给operator()加const(如排序规则的仿函数);
加const后,常量对象也能调用该运算符。

3、与 lambda 表达式的关系:

C++11 后的 lambda 表达式本质是编译器自动生成的 “匿名仿函数”;
上述排序示例用 lambda 简化:

sort(students.begin(), students.end(), 
     [](const pair<string, int>& a, const pair<string, int>& b) {
         return a.second > b.second;
     });

4、重载多个版本:

可根据参数类型 / 个数重载多个operator(),满足不同调用场景:

class Calc {
public:
    int operator()(int a, int b) const { return a + b; }
    double operator()(double a, double b) const { return a * b; }
    int operator()(int a) const { return a * 2; }
};

// 调用
Calc calc;
cout << calc(3,5) << endl;    // 8(int加法)
cout << calc(2.5, 4.0) << endl;// 10.0(double乘法)
cout << calc(6) << endl;       // 12(int翻倍)

5、不可重载为全局函数:

operator() 是成员函数专属的重载运算符,全局函数无法重载(因为对象()的语法要求左操作数是类对象)。

六、总结

函数调用运算符重载的核心价值是:
让类对象拥有 “函数行为”,兼具函数的灵活性和类的状态管理能力;
是 STL 算法自定义逻辑的核心手段,也是 lambda 表达式的底层支撑;
重载时需注意const修饰(无状态时必加),并根据场景设计参数和返回值。
相比普通函数,函数对象(仿函数)在需要 “带状态的函数逻辑” 或 “重载不同参数的函数行为” 时,优势尤为明显。

到此这篇关于c++中函数调用运算符重载的实现的文章就介绍到这了,更多相关c++ 函数调用运算符重载内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 浅析c++函数参数和返回值

    浅析c++函数参数和返回值

    c++一直以来是一个关注效率的代码,这样关于函数的参数传递和返回值的接收,是重中之重,这篇文章主要介绍了c++函数参数和返回值,需要的朋友可以参考下
    2023-05-05
  • C语言实现顺序表的基本操作指南(注释很详细)

    C语言实现顺序表的基本操作指南(注释很详细)

    线性表是最简单的数据结构,而顺序表又是最简单的线性表,其基本思想是用一段地址连续的储存单元依次存储线性表的数据元素,下面这篇文章主要给大家介绍了关于C语言实现顺序表的基本操作,需要的朋友可以参考下
    2021-10-10
  • Qt快速读取大文件最后一行内容解决方案

    Qt快速读取大文件最后一行内容解决方案

    这篇文章主要给大家介绍了关于Qt如何快速读取大文件最后一行内容的解决方案,文中通过代码介绍的非常详细,对大家学习或者使用Qt具有一定的参考借鉴价值,需要的朋友可以参考下
    2024-01-01
  • 推荐几款实用的C++ 在线工具

    推荐几款实用的C++ 在线工具

    这篇文章主要推荐了几款实用的C++ 在线工具,帮助大家更好的进行c++开发,感兴趣的朋友可以了解下载。
    2020-10-10
  • C语言实现查询自动售货机中的商品价格【实例分享】

    C语言实现查询自动售货机中的商品价格【实例分享】

    本文主要介绍了C语言实现查询自动售货机中的商品价格的相关资料。具有很好的参考价值。下面跟着小编一起来看下吧
    2017-04-04
  • C++实现LeetCode(152.求最大子数组乘积)

    C++实现LeetCode(152.求最大子数组乘积)

    这篇文章主要介绍了C++实现LeetCode(152.求最大子数组乘积),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • C++虚继承的实现原理由内存布局开始讲起

    C++虚继承的实现原理由内存布局开始讲起

    为了解决多继承时的命名冲突和冗余数据问题,C++提出了虚继承,使得在派生类中只保留一份间接基类的成员,下面我们从内存布局看看虚继承的实现原理
    2022-06-06
  • C++中Copy-Swap实现拷贝交换

    C++中Copy-Swap实现拷贝交换

    本文主要介绍了C++中Copy-Swap实现拷贝交换,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • C语言中几种常量的认识和理解

    C语言中几种常量的认识和理解

    这篇文章主要为大家介绍了C语言常量的认识和理解,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2021-12-12
  • C++ 右值引用(rvalue references)与移动语义(move semantics)深度解析

    C++ 右值引用(rvalue references)与移动语义(move semanti

    文章主要介绍了C++右值引用和移动语义的设计动机、基本概念、实现方式以及在实际编程中的应用,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2025-12-12

最新评论