当前位置: 首页 > 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 将暂存区的文件恢复到工…...

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

java_网络服务相关_gateway_nacos_feign区别联系

1. spring-cloud-starter-gateway 作用&#xff1a;作为微服务架构的网关&#xff0c;统一入口&#xff0c;处理所有外部请求。 核心能力&#xff1a; 路由转发&#xff08;基于路径、服务名等&#xff09;过滤器&#xff08;鉴权、限流、日志、Header 处理&#xff09;支持负…...

基于服务器使用 apt 安装、配置 Nginx

&#x1f9fe; 一、查看可安装的 Nginx 版本 首先&#xff0c;你可以运行以下命令查看可用版本&#xff1a; apt-cache madison nginx-core输出示例&#xff1a; nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...

LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》

这段 Python 代码是一个完整的 知识库数据库操作模块&#xff0c;用于对本地知识库系统中的知识库进行增删改查&#xff08;CRUD&#xff09;操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 &#x1f4d8; 一、整体功能概述 该模块…...

【SpringBoot自动化部署】

SpringBoot自动化部署方法 使用Jenkins进行持续集成与部署 Jenkins是最常用的自动化部署工具之一&#xff0c;能够实现代码拉取、构建、测试和部署的全流程自动化。 配置Jenkins任务时&#xff0c;需要添加Git仓库地址和凭证&#xff0c;设置构建触发器&#xff08;如GitHub…...

Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement

Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...

Python实现简单音频数据压缩与解压算法

Python实现简单音频数据压缩与解压算法 引言 在音频数据处理中&#xff0c;压缩算法是降低存储成本和传输效率的关键技术。Python作为一门灵活且功能强大的编程语言&#xff0c;提供了丰富的库和工具来实现音频数据的压缩与解压。本文将通过一个简单的音频数据压缩与解压算法…...

全面解析数据库:从基础概念到前沿应用​

在数字化时代&#xff0c;数据已成为企业和社会发展的核心资产&#xff0c;而数据库作为存储、管理和处理数据的关键工具&#xff0c;在各个领域发挥着举足轻重的作用。从电商平台的商品信息管理&#xff0c;到社交网络的用户数据存储&#xff0c;再到金融行业的交易记录处理&a…...