C++系列-函数对象/仿函数

news/2025/1/21 18:34:07/

函数对象/仿函数

  • 💢什么是仿函数
  • 💢仿函数的使用
    • 💢💢像普通函数一样使用
    • 💢💢可以有自己的状态
    • 💢💢可以作为函数的参数
    • 💢💢可以作为模板参数
    • 💢💢可以作为容器相关的算法的参数


李清照《声声慢·寻寻觅觅》
寻寻觅觅,冷冷清清,凄凄惨惨戚戚。乍暖还寒时候,最难将息。三杯两盏淡酒,怎敌他、晚来风急!雁过也,正伤心,却是旧时相识。
满地黄花堆积,憔悴损,如今有谁堪摘?守着窗儿,独自怎生得黑?梧桐更兼细雨,到黄昏、点点滴滴。这次第,怎一个愁字了得!


💢什么是仿函数

  • 🥝仿函数,即函数对象,并不是一个函数,它是与类相关的
  • 🥝一个类或者结构体的定义如果重载了()操作符,那么可以称为仿函数类,或者函数对象的类型。
  • 🥝仿函数类实例的对象,可以称为具体的函数对象,仿函数对象。
  • 🥝函数对象在使用上和函数非常相似(只针对于重载的()操作符)。

💢仿函数的使用

💢💢像普通函数一样使用

  • 🍓 函数对象在使用时,可以像普通函数那样调用,可以有参数,可以有返回值

👉👉👉
在下面的代码中,MyPrint obj_print; 创建了一个函数对象,而它在使用()运算符时,像函数的调用。
string result = obj_print(“Sure. when is it?”); ,可以有参数,可以有返回值。

#include <iostream>
using namespace std;template<class T>
void my_print(T& val)
{cout << val << " ";
}template<class T>
class MyPrint
{
public:T operator()(const T& val){cout << val << endl;return val;}
};void test01()
{string s = "Can you come to my birthdat party?";my_print(s); // 使用普通的函数cout << endl;MyPrint<string> obj_print; // 创建函数对象// 函数对象在使用()重载成员函数时,像使用函数一样可以有参数,有返回值string result = obj_print("Sure. when is it?"); cout << result << endl;
}int main()
{test01();system("pause");return 0;
}result:
Can you come to my birthdat party?
Sure. when is it?
Sure. when is it?

💢💢可以有自己的状态

  • 🍉 函数对象在使用时,因为它本身是个对象,其成员,其它函数都可以正常使用,所以还可以记录状态

👉👉👉
在下面的代码中,m_count用来计数函数被调用过几次。
get_count()为状态提供了接口。

code:
#include <iostream>
using namespace std;template<class T>
class MyPrint
{
public:MyPrint(){m_count = 0;}T operator()(const T& val){m_count++;cout << val << endl;return val;}int get_count(){return m_count;		// 可以用来记录状态}
private:int m_count;
};void test01()
{MyPrint<string> my_print1; // 创建函数对象// 函数对象在使用()重载成员函数时,像使用函数一样可以有参数,有返回值for (int i_loop = 0; i_loop < 5; i_loop++){my_print1("Orange is my favorite color.");}cout << "the numbers of the function call: " << my_print1.get_count() << endl;
}int main()
{test01();system("pause");return 0;
}result:
Orange is my favorite color.
Orange is my favorite color.
Orange is my favorite color.
Orange is my favorite color.
Orange is my favorite color.
the numbers of the function call: 5

💢💢可以作为函数的参数

👉👉👉
在下面的代码中,my_print1作为print_func的参数。
因为函数对象它本身是个对象,它可以作为函数参数。

code:
#include <iostream>
using namespace std;template<class T>
class MyPrint
{
public:T operator()(const T& val){cout << val << endl;return val;}
};template<class T>
void print_func(MyPrint<T> &my_print, string info)
{my_print(info);
}void test01()
{MyPrint<string> my_print1; // 创建函数对象// 函数对象作为参数print_func(my_print1, "It's on sunday.");
}int main()
{test01();system("pause");return 0;
}result:
It's on sunday.

💢💢可以作为模板参数

👉👉👉
仿函数类可以作为模板参数。
因为它本身就是一种类型。

code:
#include <iostream>
using namespace std;class MyPrint
{
public:string operator()(const string & val){cout << val << endl;return val;}
};template<class T>
void print_func(T & my_print, string info)		// 
{my_print(info);
}void test01()
{MyPrint my_print1; // 创建函数对象// 仿函数类作为模板参数print_func<MyPrint>(my_print1, "It starts at two o'clock in the afternoon.");
}int main()
{test01();system("pause");return 0;
}result:
It starts at two o'clock in the afternoon.

💢💢可以作为容器相关的算法的参数

code:
#include <iostream>
using namespace std;
#include <vector>
#include <algorithm>template<class T>
void my_print(T & val)
{cout << val << " ";
}template<class T>
class MyPrint
{
public:MyPrint(){cout << "默认构造函数" << endl;}MyPrint(const int& val){cout << "有参构造函数" << endl;}void operator()(T& val){cout << val << " ";}
};template<class T>
void print_vector(vector<T>& vec)
{for_each(vec.begin(), vec.end(), MyPrint<T>());
}void test01()
{vector<int> vec1{1, 5, 56, 23, 11, 4};// MyPrint2<int>(10)是匿名对象,因为MyPrint2类中重载了操作符(),故MyPrint2<int>(10)是一个函数对象for_each(vec1.begin(), vec1.end(), MyPrint<int>(10));	cout << endl;vector<float> vec2{1.1, 5.5, 56.3, 23.8, 11.5, 4.7};// 对于for_each中的第三个参数,可以是普通的函数,也可以是函数对象for_each(vec2.begin(), vec2.end(), my_print<float>);cout << endl;// MyPrint2<int>()是匿名对象,因为MyPrint2类中重载了操作符(),故MyPrint2<int>()是一个函数对象for_each(vec2.begin(), vec2.end(), MyPrint<float>());cout << endl;
}result:
有参构造函数
1 5 56 23 11 4
1.1 5.5 56.3 23.8 11.5 4.7
默认构造函数
1.1 5.5 56.3 23.8 11.5 4.7
文章来源:https://blog.csdn.net/weixin_48668114/article/details/142135668
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ppmy.cn/news/1526253.html

相关文章

ElementUI 快速入门:使用 Vue 脚手架搭建项目

文章目录 一 . ElementUI 的基本安装1.1 通过 Vue 脚手架创建项目1.2 在 vue 脚手架中安装 ElementUI1.3 编写页面 ElementUI 是 Vue.js 的强大 UI 框架&#xff0c;让前端界面开发变得简单高效。本教程将带你从安装到实战&#xff0c;快速掌握 ElementUI 的核心技巧。 核心内容…

手机玩机常识____展讯芯片刷机平台ResearchDownload的一些基本常识与问题解决

展讯ResearchDownload工具 展讯芯片的刷机工具--ResearchDownload下载工具"是一款专为用户设计的高效、便捷的下载管理软件&#xff0c;它能够帮助用户快速、稳定地从互联网上获取各种文件。这款工具以其强大的功能和良好的用户体验&#xff0c;在众多展讯芯片下载工具中脱…

【大数据方案】智慧大数据平台总体建设方案书(word原件)

第1章 总体说明 1.1 建设背景 1.2 建设目标 1.3 项目建设主要内容 1.4 设计原则 第2章 对项目的理解 2.1 现状分析 2.2 业务需求分析 2.3 功能需求分析 第3章 大数据平台建设方案 3.1 大数据平台总体设计 3.2 大数据平台功能设计 3.3 平台应用 第4章 政策标准保障体系 4.1 政策…

校园水电费管理|基于java的校园水电费管理小程序系统 (源码+数据库+文档)

校园水电费管理 目录 基于java的校园水电费管理小程序系统 一、前言 二、系统设计 三、系统功能设计 小程序端 后台功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕…

Spring Boot-API版本控制问题

在现代软件开发中&#xff0c;API&#xff08;应用程序接口&#xff09;版本控制是一项至关重要的技术。随着应用的不断迭代&#xff0c;API 的改动不可避免&#xff0c;如何在引入新版本的同时保证向后兼容&#xff0c;避免对现有用户的影响&#xff0c;是每个开发者需要考虑的…

掌握MATLAB中的图形用户界面布局管理器

在MATLAB中&#xff0c;图形用户界面&#xff08;GUI&#xff09;的设计对于创建专业且用户友好的应用至关重要。布局管理器在GUI设计中扮演着核心角色&#xff0c;它们负责在窗口中自动管理和调整控件的位置和大小。本文将详细介绍MATLAB中的布局管理器&#xff0c;包括它们的…

[PICO VR眼镜]眼动追踪串流Unity开发与使用方法,眼动追踪打包报错问题解决(Eye Tracking)

前言 最近在做一个工作需要用到PICO4 Enterprise VR头盔里的眼动追踪功能&#xff0c;但是遇到了如下问题&#xff1a; 在Unity里面没法串流调试眼动追踪功能&#xff0c;根本获取不到Device&#xff0c;只能将整个场景build成APK&#xff0c;安装到头盔里&#xff0c;才能在…

Oracle 11gR2打PSU补丁详细教程

1 说明 Oracle的PSU&#xff08;Patch Set Update&#xff09;补丁是Oracle公司为了其数据库产品定期发布的更新包&#xff0c;通常每季度发布一次。PSU包含了该季度内收集的一系列安全更新&#xff08;CPU&#xff1a;Critical Patch Update&#xff09;以及一些重要的错误修…