112 C++可调用对象整理,std::function std::bind 的使用

一 可调用对象

本节课将可调用对象整理一下

1 函数指针

void func90(int tv) {cout << "func90(int tv) called tv = " << tv << endl;
}void main() {//可调用对象  1 函数指针//方式一 1.1定义一个函数指针对象pmfvoid(*pmf)(int);//1.2将函数名赋值给函数指针pmf = func90;//1.3通过函数指针调用该函数pmf(2);//方式二 1.1 定义一个函数指针对象pmf1,并直接将函数名赋值给pmf1函数指针void(*pmf1)(int) = func90;//1.2通过函数指针调用该函数pmf1(20);
}

2.具有operator()成员函数的类对象(仿函数)

仿函数 functor,通过在类中重载()运算符 实现

//2.具有operator()成员函数的类对象仿函数()
class Teacher90 {
public:int operator()(double a ,string s) {cout << "operator()(double a ,string s) called  a = " << a <<"   s = "<<s << endl;return 111;}int operator()() {cout << "operator()called  "  << endl;return 222;}
};void main() {//2.1通过匿名对象调用Teacher90()();Teacher90()(89,"nihao");//2.2Teacher90 tea;tea();tea(90,"haode");//2.3tea.operator()();//等价于 tea();tea.operator()(80,"sdf"); //等价于 tea.(80,"sdf");}

3. 可被转换为函数指针的类对象

//3. 可被转换为函数指针的类对象
class Teacher91 {
public:using tfpoint = void(*)(int);//1.定义一个函数指针类型,operator tfpoint() {//2.将operator 和 函数指针 结合使用,这里的含义是 opearator的返回值类型为Teacher91::tfpointreturn mysfunc; //3. 需要return一个 返回值类型为Teacher91::tfpoint 的函数指针类型,因此要找一个函数返回,该函数的返回值是void,参数是int的//return NULL; 如果return NULL 会有run time exception}static void mysfunc(int tv) {cout << "Teacher91::mysfunc() 静态成员函数执行了 tv = " << tv << endl;}
};void main() {Teacher91 tea;tea(90);//先调用tfpoint()函数,再调用mysfunc函数,等价于tea.operator Teacher91::mysfunc()(90);
}

4. 类成员函数指针

注意写法有点不同

//4. 类成员函数指针
class Teacher92 {
public:void func(int vt) {cout << "void func(int vt) call vt = " << vt << endl;}
};void main() {//方式1void (Teacher92::*pointfunc)(int) = &Teacher92::func;Teacher92 tea;(tea.*pointfunc)(89);//方式2void (Teacher92::*pointfunc1)(int);pointfunc1 = &Teacher92::func;Teacher92 tea1;(tea1.*pointfunc1)(99989);
}

5.总结

二 std::function(可调用对象包装器)

如何把上述4种不同的可调用对象的形式统一一下,统一的目的是方便咱们调用。

就要用到 function 可调用对象包装器。

要使用function 可调用对象包装器,先要include functional

#include <functional>

1. std::function  是一个类模版,用来装各种可调用对象,但是不能装类成员函数指针

std::function 类模版的特点:就是能够通过给它指定模版参数,它就能够用统一的方式来处理函数。

0.不能绑定类成员函数指针

1.绑定普通函数

//1.使用function 包装普通函数
void func100(int tv) {cout << "func100(int tv) called tv = " << tv << endl;
}void main() {function<void(int)> fu1 = func100;fu1(200);
}

2.绑定类的静态成员函数

//2.绑定类的静态成员函数
class Teacher93 {
public:static void teacher93staticfunc(int tv) {cout << "Teacher93::teacher93staticfunc(int tv) called tv = " << tv << endl;}
};void main() {function<void(int)> fu1 = Teacher93::teacher93staticfunc;fu1(900);
}

3.绑定仿函数

//3.绑定仿函数
class Teacher94 {
public:int operator()(double d, string s) {cout << "int operator()(double d, string s) called d = " << d <<  "  s = " << s << endl;return 800;}
};void main() {Teacher94 tea;double dou = 89.8;string str = "nihao";function<int(double, string)> f1 = tea;//注意这里,直接将类对象 tea 直接赋值过去。f1(dou, str);
}

4.范例演示

范例1:

//4.范例演示
class Teacher95 {
private://成员变量为 function<void()> 类型std::function<void()> fcallback;public://再构造方法中,参数也是一个 std::function<void()> 类型的变量,//在初始化列表中,将形参f 直接赋值给 私有成员 fcallbackTeacher95(const std::function<void()> f):fcallback(f) {}public://再提供一个 函数,当调用这个函数的时候,直接调用 私有成员 fcallbackvoid runcallback() {fcallback();}};class Teacher96 {
public:void operator()() {cout << "Teacher96 的 operator() 函数被调用" << endl;}
};void main() {Teacher96 tea96;Teacher95 tea95(tea96);//tea95是需要一个 可调用对象 作为参数的,而tea96因为重写了operator函数,因此就是一个可调用对象tea95.runcallback();
}

范例2:

int func110(double d, string s) {cout << "func110(double d, string s) called d = " <<d <<"  s = " <<s << endl;return 800;
}void func113(double dou ,string str, const std::function<int(double,string)> &f1) {f1(dou, str);
}void main() {func113(89.8,"nihao", func110);
}

三,std::bind绑定器

是个类模版 ,C++  引入

从实际写的方法中,可以看到,这个类模版

#include <functional>

作用:

1.能够将对象以及相关的参数绑定在一起,绑定完后可以直接调用。

2.也可以用std::function进行保存,在需要的时候保存

格式:

std::bind(待绑定的函数对象,参数绑定值1,参数绑定值2......参数绑定值n)

总结:

a.将可调用对象和参数绑定在一起,所以可以直接调用

f-可调用 (Callable) 对象(函数对象、指向函数指针、到函数引用、指向成员函数指针或指向数据成员指针)

b.如果函数有多个参数,可以绑定一部分参数,其他参数在调用的时候指定。

返回值:

是一个可调用对象类型

1.将普通函数的对象和参数绑定

//1.能够将对象以及相关的参数绑定在一起,绑定完后可以直接调用。void func120(int x ,int y ,int z) {cout << "x = " << x << " y = " << y << "  z = " << z << endl;
}//关于普通函数的绑定
void main() {//1直接匿名调用bind(func120, 10, 20, 30)();//2.使用bind 获得返回值,那么bind的返回值类型是啥呢?查看 C++文档,bind 绑定不同的类型,返回值也不同,长长一大堆,查看了文档给出来的例子,都是用auto,因此我们这里也用autoauto b1 = bind(func120, 100, 203, 302);b1();//3.上述我们都是将三个参数的值都写死了,如果我们只想绑定一部分参数,该怎么写呢?//3.1 让参数1 和参数2的值相等auto b2 = bind(func120, std::placeholders::_1, std::placeholders::_1, 898);b2(567);//3.2 让参数1 和参数2的值bu 相等auto b3 = bind(func120, std::placeholders::_1, std::placeholders::_2, 1234);b3(8978,678);//3.3 注意,我们这里是用b2再调用,但是仍然可以调用,只是第二个参数56789没有用b2(8978, 56789);//3.4 ,参考前面的,如果想要实参的第一个不发挥作用,则这么写auto b4 = bind(func120, std::placeholders::_2, std::placeholders::_2, 90);b4(8, 9);//解释:std::placeholders::_1, std::placeholders::_2都是占位符,表示的含义是:将来用实参的第一个参数,和 实参的第二个参数来替代我//由于bind 的返回值是一个可调用对象,结合前面学习的function,就可以使用function 将其保存起来}

2.将普通函数的对象和参数绑定 坑定1

bind对于预先绑定的函数参数 是通过值传递的,因此a 和 b 是值传递的
bind对于不事先 绑定的参数,通过std::placeholders传递的参数,真正调用的函数的 形参类型是啥,std::placeholders占位的实参的类型就是啥
 

void func121(int &x, int &y, int &z) {++x;++y;++z;cout << "func121 x = " << x << " y = " << y << "  z = " << z << endl;
}void main() {int a = 10;int b = 20;int c = 30;auto b1 = bind(func121, a, b, std::placeholders::_1);b1(c);cout << "main a = " << a << " b = " << b << "  c = " << c << endl;//结果://  func121 x = 11 y = 21  z = 31//	main a = 10 b = 20  c = 31//这说明:bind对于预先绑定的函数参数 是通过值传递的,因此a 和 b 是值传递的// bind对于不事先 绑定的参数,通过std::placeholders传递的参数,真正调用的函数的 形参类型是啥,std::placeholders占位的实参的类型就是啥}

3.绑定 类的函数

注意调用方式,以及坑点。

调用方式: 

bind(函数地址,类对象,参数一,参数二)

    auto b1 = bind(&Teacher122::Teacher122func, tea, age, "nihao");
    b1();

bind(函数地址,类对象引用,参数一,参数二)

    auto b2 = bind(&Teacher122::Teacher122func, &tea, 678, "uio");
    b2();

auto b3 = bind(&Teacher122::Teacher122func, &tea, std::placeholders::_1, std::placeholders::_2);

b3(56,"sss");

坑点:

第二个参数,传递类对象,实际上会调用 copy 构造函数,生成一个临时对象进去,那么参数都是临时对象的,返回值肯定可以临时对象的,因此在代码中真正改动的也是 临时对象的mage。

如果想要真正的改动类对象中的值,需要使用引用。

class Teacher122 {public:Teacher122() {cout << "Teacher122 构造函数called" << endl;}Teacher122(const Teacher122 & obj) {this->mage = obj.mage;cout << "Teacher122 copy 构造函数 called" << endl;}Teacher122 & operator=(Teacher122 & obj) {this->mage = obj.mage;cout << "Teacher122 operator= 函数called" << endl;return *this;}virtual ~Teacher122() {cout << "Teacher122 析构函数 被调用" << endl;}double Teacher122func(int dou,string str) {cout << "Teacher122func called dou = " << dou << "  str = " << str << endl;this->mage = dou;return 3.1415926;}public :int mage;
};void main() {Teacher122 tea;int age = 980;auto b1 = bind(&Teacher122::Teacher122func, tea, age, "nihao");b1();//再还没有运行前,我们可以分析一下,age的值,会被赋值给tea.mage,因此mage的值 我们推导应该是980cout << "tea.mage = " << tea.mage << endl;//运行发现,tea.mage的值是一个随机值,这很诡异,明明给mage赋值了980呀。//添加 构造函数,copy构造函数,operator=函数,析构函数再次运行,发现有copy构造函数运行。//那么这个tea,在bind函数调用的时候,bind(&Teacher122::Teacher122func, tea, age, "nihao");是否copy了一份临时对象呢?//测试还真是的。//结论:bind 在对类成员函数的绑定的时候,如果传递的是类对象实例,实际上 会 传递的是临时对象: copy 构造函数会被调用//那么问题又来了,如果我们就是想要赋值mage的值,怎么办呢?//fix 方案,传递一个引用就好了auto b2 = bind(&Teacher122::Teacher122func, &tea, 678, "uio");b2();cout << "use 引用后的结果 tea.mage = " << tea.mage << endl;auto b3 = bind(&Teacher122::Teacher122func, &tea, std::placeholders::_1, std::placeholders::_2);b3(56,"sss");cout << "use 引用后的结果22 tea.mage = " << tea.mage << endl;cout << "duandian" << endl;//Teacher122 构造函数called//Teacher122 copy 构造函数 called//Teacher122func called dou = 980  str = nihao//tea.mage = -858993460//Teacher122func called dou = 678  str = uio//use 引用后的结果 tea.mage = 678//Teacher122func called dou = 56  str = sss//use 引用后的结果22 tea.mage = 56//duandian//Teacher122 析构函数 被调用//Teacher122 析构函数 被调用
}

4.bind 和function 配合使用

function 的作用是 :可调用对象包装器,意思就是将这些 可调用对象 包装起来

bind的作用是 : 将对象和参数绑定,返回一个 可调用对象。

发现了吗:因此bind的返回值,可以直接用function 包起来

//4.bind 和function 配合使用void func126(int vt) {cout << "func126(int vt) vt = " << vt << endl;
}void main() {auto b1 = bind(func126, std::placeholders::_1);function<void(int)> f1 = b1;f1(11);
}

5. bind 还能绑定 成员变量,绑定完成后还能放在 function 中。感觉这个没啥用呀,记录一下。

注意写法。

注意引用。

class Teacher127 {
public:int mage;
};void main() {Teacher127 tea127;auto b1 = bind(&Teacher127::mage, &tea127);b1() = 90;cout << tea127.mage << endl;function<int &()> f1 = b1;f1() = 89090;cout << tea127.mage << endl;
}

6. bind 绑定 类对象,该类对象需要实现 operator()的重写。

class Teacher128 {
public:int mage;public:void operator()(int a ) {cout << "Teacher128 operator()(int a ) called a =" << a << endl;}
};void main() {Teacher128 tea;auto b1 = bind(tea, std::placeholders::_1);b1(89);
}

四 总结

bind的思想:所谓的延迟调用,将可调用对象统一格式,保存起来,需要的额时候再调用。

function 绑定一个可调用对象,但是类成员函数不能绑定。

std::bind则可以将类成员函数,类成员变量都能绑。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/688666.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【工作向】版本管理-IPD流程简介

1. IPD的由来 Integrated Product Development&#xff0c;集成产品开发 从IBM引进并结合自身实践 2. 引入IPD的过程 突破期 -> 全面推行期 -> 与时俱进发展 -> IPD2.0 19年开始 版本 -> 项目 -> 产品 产品开发流程&#xff0c;需求管理流程&#xff0c;生…

2024最新软件测试八股文(答案+文档)

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号【互联网杂货铺】&#xff0c;回复 1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 1、B/S架构和C/S架构区别 B/S 只需要有操作系统和浏览器就行&a…

PAT (Basic Level) Practice | A+B 和 C

给定区间 [−2的31次方, 2的31次方] 内的 3 个整数 A、B 和 C&#xff0c;请判断 AB 是否大于 C。 输入格式&#xff1a; 输入第 1 行给出正整数 T (≤10)&#xff0c;是测试用例的个数。随后给出 T 组测试用例&#xff0c;每组占一行&#xff0c;顺序给出 A、B 和 C。整数间…

运行错误(竞赛遇到的问题)

在代码提交时会遇见这样的错误&#xff1a; 此处运行错误不同于编译错误和答案错误&#xff0c;运行错误是指是由于在代码运行时发生错误&#xff0c;运行错误可能是由于逻辑错误、数据问题、资源问题等原因引起的。这些错误可能导致程序在运行时出现异常、崩溃。 导致不会显示…

机器学习2---逻辑回归(基础准备)

逻辑回归是基于线性回归是直线分的也可以做多分类 ## 数学基础 import numpy as np np.pi # 三角函数 np.sin() np.cos() np.tan() # 指数 y3**x # 对数 np.log10(10) np.log2(2) np.e np.log(np.e) #ln(e)# 对数运算 # log(AB) log(A) logB np.log(3*4)np.log(3)np.log(4) #…

Linux之Shell

第 1 章 Shell 概述 1&#xff09;Linux 提供的 Shell 解析器有 [zhaohadoop101 ~]$ cat /etc/shells /bin/sh /bin/bash /usr/bin/sh /usr/bin/bash /bin/tcsh /bin/csh2&#xff09;bash 和 sh 的关系 [zhaohadoop101 bin]$ ll | grep bash -rwxr-xr-x. 1 root root 941880…

如何利用测评自养号成功运营沃尔玛、阿里国际等跨境平台?

沃尔玛&#xff0c;自1962年成立以来&#xff0c;已稳居全球最大零售商的行列&#xff0c;并连续多年荣登世界500强企业的榜单。凭借强大的企业实力和卓越的市场表现&#xff0c;该公司在美国《财富》杂志2014-2016年全球最大500家公司的评选中荣登榜首。如今&#xff0c;沃尔玛…

VFH特征的使用(一)

一、SHOT特征描述符可视化 C #include <pcl/point_types.h> #include <pcl/point_cloud.h> #include <pcl/io/pcd_io.h> #include <pcl/features/normal_3d_omp.h> #include <pcl/registration/correspondence_estimation.h> #include <boo…

xtu oj 1170 ICPC 2.0

题目描述 ACM/ICPC比赛涉及的知识点非常多&#xff0c;一个队伍三个人需要能够互补。一个队伍某个知识点的高度是三个人中水平最高的那个人决定。现在给你三个人的每个知识点的水平情况&#xff0c;请计算一下这个队伍的水平。 输入 存在多个样例。每个样例的第一行是一个整…

王力宏胜诉,事实胜于雄辩,真相终将大白。

♥ 为方便您进行讨论和分享&#xff0c;同时也为能带给您不一样的参与感。请您在阅读本文之前&#xff0c;点击一下“关注”&#xff0c;非常感谢您的支持&#xff01; 文 |猴哥聊娱乐 编 辑|徐 婷 校 对|侯欢庭 好的&#xff0c;以下是对“2月5日&#xff0c;王力宏工作室在…

echarts制作两个柱状图

let colorList[#02ce8b,#ffbe62,#f17373]; let data1 [90,80,70,50] option { title:[{ // 第一个标题text: 环保检测, // 主标题textStyle: { // 主标题样式color: #333,fontWeight: bold,fontSize: 16},left: 20%, // 定位到适合的位置top: 10%, // 定位到适合的位置},{ //…

基于Springboot的新能源充电系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的新能源充电系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&a…

IO 作业 24/2/18

1> 使用fgets统计给定文件的行数 #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, const char *argv[]) {//定义文件指针FILE *fpNULL;//打开文件&#xff08;只读&#xff09;if((fpfopen("./test.txt",&quo…

bat 定时收缩日志sqlserver2012

在SQL Server中&#xff0c;定期收缩事务日志&#xff08;transaction log&#xff09;通常不是一个好的做法&#xff0c;因为事务日志的收缩和增长是数据库正常操作的一部分。频繁地收缩事务日志可能会导致性能问题&#xff0c;增加I/O负担&#xff0c;并可能导致事务日志碎片…

300分钟吃透分布式缓存-01讲:业务数据访问性能太低怎么办?

这节课主要讲缓存的基本思想、缓存的优点、缓存的代价三个部分。 缓存的定义 先来看下缓存的定义。 & 缓存最初的含义&#xff0c;是指用于加速 CPU 数据交换的 RAM&#xff0c;即随机存取存储器&#xff0c;通常这种存储器使用更昂贵但快速的静态 RAM&#xff08;SRAM&…

python数据分析numpy基础之mean用法和示例

1 python数据分析numpy基础之mean用法和示例 python的numpy库的mean()函数&#xff0c;用于计算沿指定轴(一个轴或多个轴)的算术平均值。 用法 numpy.mean(a, axisNone, dtypeNone, outNone, keepdims<no value>, *, where<no value>)描述 返回数组元素的平均值…

Airtest-Selenium实操小课:爬取新榜数据

1. 前言 最近看到群里很多小伙伴都在用Airtest-Selenium做一些web自动化的尝试&#xff0c;正好趁此机会&#xff0c;我们也出几个关于web自动化的实操小课&#xff0c;仅供大家参考~ 今天跟大家分享的是一个非常简单的爬取网页信息的小练习&#xff0c;在百度找到新榜网页&a…

【精选】Java面向对象进阶——接口细节:成员特点和接口的各种关系

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏 …

鸿蒙生态来了 ,60k 高薪向你招手

最近&#xff0c;各大平台都被华为鸿蒙不断刷屏。原因是在华为秋季发布会上&#xff0c;华为宣布启动鸿蒙原生应用&#xff0c;不再兼容安卓应用。一石激起千层浪&#xff0c;这无疑是IT界的一颗核弹&#xff0c;各大企业和开发者都纷纷开始加入“鸿蒙朋友圈”。 鸿蒙原生应用…

【机构vip教程】Requests(1):Requests模块简介与安装

Requests模块简介 在python的标准库中&#xff0c;虽然提供了urllib,utllib2,httplib&#xff0c;但是做接口测试&#xff0c;requests使用更加方便快捷&#xff0c;正如官方说的&#xff0c;“让HTTP服务人类”。 Requests是用python语言基于urllib编写的&#xff0c;采用的是…