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

C++之可调用对象、bind绑定器和function包装器

可调用对象

在C++中,可以像函数一样调用的有:普通函数、类的静态成员函数、仿函数、lambda函数、类的非静态成员函数、可被转换为函数的类的对象,统称可调用对象或函数对象。

可调用对象有类型,可以用指针存储它们的地址,可以被引用(类的成员函数除外)。

这里举几个例子

仿函数(本质是重载了()的类)

#include<iostream>
using namespace std;
struct Object
{void operator()(int age, string name){cout << "年龄:" << age << ",姓名:" << name << endl;}
};
int main()
{Object obj;obj(20, "小谢");Object& obj_r = obj;    // 引用函数obj_r(19, "小赵");return 0;
}

lambda函数

#include<iostream>
using namespace std;
int main()
{auto func = [](int age, string name){cout << "年龄:" << age << ",姓名:" << name << endl;};func(20, "小谢");auto& func_r = func;// 引用lambda对象。func_r(19, "小赵");return 0;
}

类的非静态成员函数

类的非静态成员函数有地址,但是,只能通过类的对象才能调用它,所以,C++对它做了特别处理。

类的非静态成员函数只有指针类型,没有引用类型,不能引用。

#include<iostream>
using namespace std;
struct Object
{void show(int age, string name){cout << "年龄:" << age << ",姓名:" << name << endl;}
};
int main()
{Object obj;obj.show(20, "小谢");void(Object::*pobj)(int, string) = &Object::show;// 定义类的成员函数的指针。(obj.*pobj)(19, "小赵");using PFun = void(Object::*)(int, string);PFun p_show = &Object::show;(obj.*p_show)(18, "芜湖");return 0;
}

在上面的例子中满足条件的这些可调用对象对应的类型被统称为可调用类型。C++ 中的可调用类型虽然具有比较统一的操作形式,但定义方式五花八门,这样在我们试图使用统一的方式保存,或者传递一个可调用对象时会十分繁琐。现在,C++11通过提供std::function 和 std::bind统一了可调用对象的各种操作。

包装器function

包含头文件:#include <functional>

std::function<返回值类型(参数类型列表)> diy_name = 可调用对象;

#include<iostream>
#include<functional>
using namespace std;
int add(int a, int b)
{cout << a << "+" << b << "=" << a + b << endl;return a + b;
}
class T
{
public:static int sub(int a, int b){cout << a << "*" << b << "=" << a * b << endl;return a * b;}
};
class T1
{
public:int operator()(int a, int b){cout << a << "-" << b << "=" << a - b << endl;return a - b;}
};
int main()
{//std::function<返回值类型(参数类型列表)> diy_name = 可调用对象;function<int(int, int)> f1 = add;f1(1, 2);function<int(int, int)> f2 = T::sub;f2(2, 3);T1 t;function<int(int, int)> f3 = t;f3(3, 4);return 0;
}

通过测试代码可以得到结论:std::function 可以将可调用对象进行包装,得到一个统一的格式,包装完成得到的对象相当于一个函数指针,和函数指针的使用方式相同,通过包装器对象就可以完成对包装的函数的调用了。

作为回调函数使用

#include <iostream>
#include <functional>
using namespace std;
class A
{
public:// 构造函数参数是一个包装器对象A(const function<void()>& f) : callback(f){}void notify(){callback(); // 调用通过构造函数得到的函数指针}
private:function<void()> callback;  //成员变量->包装器对象
};class B
{
public:void operator()(){cout << "!!!" << endl;}
};
int main(void)
{B b;A a(b);a.notify();return 0;
}

绑定器bind

std::bind()模板函数是一个通用的函数适配器(绑定器),它用一个可调用对象及其参数,生成一个新的可调用对象,以适应模板。

函数原型

template< class Fx, class... Args >function<> bind (Fx&& fx, Args&...args);
Fx:需要绑定的可调用对象
args:/*绑定参数列表,可以是左值、右值和参数占位符std::placeholders::_n,如果参数不是占位符,缺省为值传递,std:: ref(参数)则为引用传递。*/

std::bind()返回std::function的对象。

std::bind()的本质是仿函数。

// 绑定非类成员函数/变量
auto f = std::bind(可调用对象地址, 绑定的参数/占位符);
// 绑定类成员函/变量
auto f = std::bind(类函数/成员地址, 类实例对象地址, 绑定的参数/占位符);

类成员函数需要绑定该类的this指针 。

#include<iostream>
#include<functional>
using namespace std;
struct Object
{void operator()(int age, string name){cout << "年龄:" << age << ",姓名:" << name << endl;}void show(int age, string name){cout << "年龄:" << age << ",姓名:" << name << endl;}};
int main()
{Object obj;function<void(int, string)> f1 = bind(Object(), placeholders::_1, placeholders::_2);f1(20, "小谢");auto func = [](int age, string name){cout << "年龄:" << age << ",姓名:" << name << endl;};function<void(int, string)> f2 = bind(func, placeholders::_1, placeholders::_2);f2(19, "小赵");// 类成员函数需要绑定该类的this指针  Object obj1;function<void(Object&, int, string)> f3 = bind(&Object::show, placeholders::_1, placeholders::_2, placeholders::_3);f3(obj1,17,"张三");//这里为了统一,将对象提前绑定function<void(int, string)> f4 = bind(&Object::show, obj1, placeholders::_1, placeholders::_2);f4(16, "李四");return 0;
}

在用绑定器绑定类成员函数或者成员变量的时候需要将它们所属的实例对象一并传递到绑定器函数内部。

bind的应用

改变参数位置

例如函数需要一个int和string两个参数

auto f = bind(func, placeholders::_1, placeholders::_2);

第一个参数为int,第二个为string,但是如果第一个想第一个传入string,第二个传入int

auto f = bind(func, placeholders::_2, placeholders::_1);

改变参数个数

改变参数个数主要是为了统一,便于使用函数模板,例如上述例子的部分代码

Object obj1;
function<void(Object&, int, string)> f3 
= bind(&Object::show, placeholders::_1, placeholders::_2, placeholders::_3);
f3(obj1,17,"张三");
//这里为了统一,将对象提前绑定
function<void(int, string)> f4 = bind(&Object::show, obj1, placeholders::_1, placeholders::_2);
f4(16, "李四");

这里采取的是提前绑定,将对象提前绑定。

设置类成员函数为回调函数

在讲bind时上面已演示!!

相关文章:

C++之可调用对象、bind绑定器和function包装器

可调用对象在C中&#xff0c;可以像函数一样调用的有&#xff1a;普通函数、类的静态成员函数、仿函数、lambda函数、类的非静态成员函数、可被转换为函数的类的对象&#xff0c;统称可调用对象或函数对象。可调用对象有类型&#xff0c;可以用指针存储它们的地址&#xff0c;可…...

MongoDB--》文档查询的详细具体操作

目录 统计查询 分页列表查询 排序查询 正则的复杂条件查询 比较查询 包含查询 条件连接查询 统计查询 统计查询使用count()方法&#xff0c;其语法格式如下&#xff1a; db.collection.count(query,options) ParameterTypeDescriptionquerydocument查询选择条件optio…...

网络协议(六):网络层

网络协议系列文章 网络协议(一)&#xff1a;基本概念、计算机之间的连接方式 网络协议(二)&#xff1a;MAC地址、IP地址、子网掩码、子网和超网 网络协议(三)&#xff1a;路由器原理及数据包传输过程 网络协议(四)&#xff1a;网络分类、ISP、上网方式、公网私网、NAT 网络…...

热启动预示生态起航的Smart Finance,与深度赋能的SMART通证

2023年初加密市场的回暖&#xff0c;意味着各个赛道都将在新的一年里走向新的叙事。最近&#xff0c;我们看到GameFi赛道也在市场回暖的背景下&#xff0c;逐渐走出阴霾。从融资数据上看&#xff0c;1月获得融资的GameFi项目共12个&#xff0c;融资突破8000万美元&#xff0c;1…...

提分必练,中创教育PMP全真模拟题分享

湖南中创教育每日五题分享来啦&#xff0c;“日日行&#xff0c;不怕千万里&#xff1b;常常做&#xff0c;不怕千万事。”&#xff0c;每日五题我们练起来&#xff01; 1、在系统测试期间&#xff0c;按已识别原因的类型或类别记录了失败测试的数量。项目经理首先需要从最大故…...

PID控制算法基础介绍

PID控制的概念 生活中的一些小电器&#xff0c;比如恒温热水器、平衡车&#xff0c;无人机的飞行姿态和飞行速度控制&#xff0c;自动驾驶等等&#xff0c;都有应用到 PID——PID 控制在自动控制原理中是一套比较经典的算法。 为什么需要 PID 控制器呢&#xff1f; 你一定用…...

Ajax 学习笔记

一、Ajax1.1 什么是AjaxAJAX Asynchronous JavaScript and XML(异步的JavaScript和XML)。Ajax是一种在无需加载整个网页的情况下&#xff0c;能够更新部分网页的技术&#xff0c;它不是一种新的编程语言&#xff0c;而是一种用于创建更好更快以及交互性更强的Web应用程序的技术…...

​力扣解法汇总1234. 替换子串得到平衡字符串​

目录链接&#xff1a; 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目&#xff1a; https://github.com/September26/java-algorithms 原题链接&#xff1a;力扣 描述&#xff1a; 有一个只含有 Q, W, E, R 四种字符&#xff0c;且长度为 n 的字符串。 假如在该…...

C++关键字之const、inline、static

C 关键字总结 1.const const是 constant 的缩写&#xff0c;本意是不变的、不易改变的意思。在C中用来修饰内置类型变量&#xff0c;自定义对象&#xff0c;成员函数&#xff0c;返回值&#xff0c;函数参数使用如下&#xff1a; //修饰普通类型变量 const int a 7; int ba;…...

【成为架构师课程系列】怎样进行概念架构(Conceptual Architecture)?

目录 前言 什么是概念架构 概念架构阶段的3个步骤 初步设计 高层分割 分层式概念服务架构 Layer:逻辑层 Tier: 物理层 按通用性分层 技术堆叠 考虑非功能需求 【禅与计算机程序设计艺术&#xff1a;更多阅读】 前言 胜兵先胜而后求战&#xff0c;败兵先站而后求胜。…...

PostgreSQL的下载安装教程(macOS、Windows)

postgresql是GIS服务端几乎不可避免要打交道的数据库。因为mysql的空间扩展真是不尽人意。所以想要学会GIS服务端知识,postgresql(下文简称pg)你是必须要会的。 首先要知道,pg是一个空间数据库,和普通数据库不同的是pg支持空间数据的存储与操作。这里所谓的空间数据一般指…...

98年的确实卷,公司新来的卷王,我们这帮老油条真干不过.....

都说00后躺平了&#xff0c;但是有一说一&#xff0c;该卷的还是卷。这不&#xff0c;前段时间我们公司来了个00后&#xff0c;工作没两年&#xff0c;跳槽到我们公司起薪18K&#xff0c;都快接近我了。后来才知道人家是个卷王&#xff0c;从早干到晚就差搬张床到工位睡觉了。 …...

软件架构知识2-系统复杂度

架构设计的真正目的&#xff1a;是为了解决软件系统复杂度带来的问题&#xff0c;一个解决方案。 系统复杂度&#xff0c;如何入手&#xff1a; 1、通过熟悉和理解需求&#xff0c;识别系统复杂性所在的地方&#xff0c;然后针对这些复杂点进行架构设计。 2、架构设计并不是要…...

JavaSE学习day4_02 数组(超级重点)

3.数组 3.1什么是数组 数组就是存储数据长度固定的容器&#xff0c;存储多个数据的数据类型要一致。 3.2数组定义格式 3.2.1第一种&#xff08;常用&#xff09; 数据类型[] 数组名 示例&#xff1a; int[] arr; double[] arr; char[] arr; 3.2.2第二种(在…...

Theano教程:Python的内存管理

在写大型程序时候的一大挑战是如何保证最少的内存使用率。但是在Python中的内存管理是比较简单的。Python显示分配内存&#xff0c;使用引用计数系统管理对象&#xff0c;当指向某一个对象的引用数变为 0 的时候&#xff0c;该对象所占的内存就会被释放。理论上听起来很不错&am…...

Linux | Liunx安装Tomcat(Ubuntu版)

目录 一、下载并上传Tomcat压缩包到Ubuntu 1.1 下载并解压 1.2 执行 startup.sh 文件 二、验证Tomcat启动是否成功 2.1 查看启动日志 2.2 查看启动进程 三、Windows访问 Tomcat 服务 四、停止 Tomcat 服务 Tomcat是一款Web服务器&#xff0c;开发Web项目基本上都会用到…...

缓冲区浅析

缓冲区 程序运行输入数据时&#xff0c;从键盘的输入先存储到缓冲区&#xff0c;只有当缓冲区满或者输入回车时程序才会真正地从缓冲区读入数据 int main() {int a, b;cin >> a >> b;return 0; }in: 1 2\n 例如这里输入空格时程序没有输出&#xff0c;而是将空格…...

Day888.MySQL是怎么保证主备一致的 -MySQL实战

MySQL是怎么保证主备一致的 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于MySQL是怎么保证主备一致的内容。 MySQL 能够成为现下最流行的开源数据库&#xff0c;binlog 功不可没。 在最开始&#xff0c;MySQL 是以容易学习和方便的高可用架构&#xff0c;被开发人…...

互联网舆情监测系统的发展阶段,TOOM互联网舆情监测系统有哪些?

互联网舆情监测系统是一种利用计算机技术对互联网上的大量信息进行实时监测、分析和评估的工具&#xff0c;旨在了解公众对某一事件、话题或品牌等的态度、情感倾向和影响力等。通过对社交媒体、论坛、新闻媒体等多个渠道的数据采集和处理&#xff0c;系统能够实现舆情事件的追…...

GIT命令操作大全

文章目录一、前言二、工作模块2.1 Workspace&#xff1a;工作区2.2 Index / Stage&#xff1a;暂存区2.3 Repository&#xff1a;本地仓库2.4Remote&#xff1a;远程仓库三、GIT基本配置四、GIT项目代码管理4.1 初始化git仓库4.2 提交到暂存区(stage)4.3 将暂存区的文件恢复到工…...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手&#xff1a;借助大模型技术&#xff0c;开发能根据用户输入的主题、风格等要求&#xff0c;生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用&#xff0c;帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

React 第五十五节 Router 中 useAsyncError的使用详解

前言 useAsyncError 是 React Router v6.4 引入的一个钩子&#xff0c;用于处理异步操作&#xff08;如数据加载&#xff09;中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误&#xff1a;捕获在 loader 或 action 中发生的异步错误替…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

Java 语言特性(面试系列1)

一、面向对象编程 1. 封装&#xff08;Encapsulation&#xff09; 定义&#xff1a;将数据&#xff08;属性&#xff09;和操作数据的方法绑定在一起&#xff0c;通过访问控制符&#xff08;private、protected、public&#xff09;隐藏内部实现细节。示例&#xff1a; public …...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

Spring Boot 实现流式响应(兼容 2.7.x)

在实际开发中&#xff0c;我们可能会遇到一些流式数据处理的场景&#xff0c;比如接收来自上游接口的 Server-Sent Events&#xff08;SSE&#xff09; 或 流式 JSON 内容&#xff0c;并将其原样中转给前端页面或客户端。这种情况下&#xff0c;传统的 RestTemplate 缓存机制会…...

23-Oracle 23 ai 区块链表(Blockchain Table)

小伙伴有没有在金融强合规的领域中遇见&#xff0c;必须要保持数据不可变&#xff0c;管理员都无法修改和留痕的要求。比如医疗的电子病历中&#xff0c;影像检查检验结果不可篡改行的&#xff0c;药品追溯过程中数据只可插入无法删除的特性需求&#xff1b;登录日志、修改日志…...

汽车生产虚拟实训中的技能提升与生产优化​

在制造业蓬勃发展的大背景下&#xff0c;虚拟教学实训宛如一颗璀璨的新星&#xff0c;正发挥着不可或缺且日益凸显的关键作用&#xff0c;源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例&#xff0c;汽车生产线上各类…...

爬虫基础学习day2

# 爬虫设计领域 工商&#xff1a;企查查、天眼查短视频&#xff1a;抖音、快手、西瓜 ---> 飞瓜电商&#xff1a;京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空&#xff1a;抓取所有航空公司价格 ---> 去哪儿自媒体&#xff1a;采集自媒体数据进…...