当前位置: 首页 > article >正文

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

函数对象/仿函数

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


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


💢什么是仿函数

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

💢仿函数的使用

💢💢像普通函数一样使用

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

👉👉👉
在下面的代码中,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


http://www.kler.cn/news/305319.html

相关文章:

  • [网络]TCP/IP协议 之 网络层IP协议(3)
  • 艾丽卡的区块链英语小课堂
  • 基于ssm+vue+uniapp的新生报到系统小程序
  • 第4步CentOS配置SSH服务用SSH终端XShell等连接方便文件上传或其它操作
  • 实战外网配置——光猫桥接+路由器PPPoE拨号+防火墙外网链路健康检查+外网流量负载均衡
  • kafka mirror maker之实现两个kafka集群之间的数据同步
  • HTML + CSS - 网页布局之一般布局浮动布局
  • JVM 体系与结构
  • Node.js 中间件与洋葱模型
  • SonicWall SSL VPN曝出高危漏洞,可能导致防火墙崩溃
  • java --- 性能优化01
  • Git使用—把当前仓库的一个分支push到另一个仓库的指定分支、基于当前仓库创建另一个仓库的分支并推送到对应仓库(mit6828)
  • 使用 easyX 库实现顺序表插入操作的可视化
  • 并发锁机制之深入理解synchronized
  • Mybatis-plus进阶篇(一)
  • 一种全新的webapi框架C#webmvc初步介绍
  • opencv之傅里叶变换
  • ZYNQ FPGA自学笔记
  • 大屏可视化常用图标效果表达
  • OCR2.0--General OCR Theory
  • 先框架后历元还是先历元后框架?
  • elementui 单元格添加样式的两种方法
  • Web 创建设计
  • RabbitMQ(高阶使用)延时任务
  • 19. 删除链表的倒数第 N 个结点【 力扣(LeetCode) 】
  • 定时任务调用OpenFegin无token认证异常
  • LAMP+WordPress
  • 服务器运维面试题4
  • 【SpringBoot】调度和执行定时任务--Quartz(超详细)
  • Ubuntu 22.04.5 LTS 发布下载 - 现代化的企业与开源 Linux