C++:函数指针进阶:看完还不用std::function来捶我

news2025/7/20 13:01:14

1:函数指针的背景

我们先简单聊一下函数指针的背景,具体使用请参考我的这篇博客

C++ :函数: 函数指针_hongwen_yul的博客-CSDN博客

假设现在有这样一段代码:C/C++中可以使用指针指向一段代码,这个指针就叫函数指针,假设有这样一段代码、

// main.cpp
#include<iostream>

int func(int a) {

    return a+1;
}


int main(){

    int (*f)(int) = func;
    printf("%p",f);
}

// 打印结果 :400526

我们定义一个函数 func() ,然后使用指针变量 f 指向该函数,然后打印该变量f 指向的地址,代码是很简单的,然后我们编译一下,看下编译后生成的指令,接下来我们重点关注fuc 函数:

 

 可以看到,编译好的函数 func 位于地址 ox400526,然后我们运行下编译好的程序,发现输出的数据和编译后的地址是一致的,这个指针变量保存了函数func 的机器指令。

所以说明:函数指针本质上也是一个指针,只不过这个指针指向的不是内存中的一段数据,而是内存中的一段代码。

 有的同学可能会有疑问,:为什么编译器在生成可执行文件时就知道函数 func 存放在内存地址 0x400526上了?这不是应该是程序被加载到内存后开始运行时,才能确定的吗?

答案就在函数指针:可以把一段代码当做一个变量传来传去,这个变量保存了这段代码地址,它的主要用途之一就是 回调函数,关于回调函数,你可以参考我的这篇文章。

C++:函数:回调函数:还不懂回调函数来捶我_hongwen_yul的博客-CSDN博客q​​​​​​回调函数------函数指针https://blog.csdn.net/u013620306/article/details/128009205?spm=1001.2014.3001.5501

其实回调函数就是这样的

 

 

2:函数指针的衍生

上面我们说到,可以定义一个指针变量来保存函数地址,但是了,假如我们我们的场景在复杂点:

我们依然需要在模块A中定义函数,同时运行模块A 需要依赖模块B产生的数据,然后将模块A定义的函数和模块B产生的数据一并传递给模块C来调用,就像这样:

 很显然单纯的函数指针已经不够用了,因为函数指针只是单纯的指向了内存中的一段代码,但是我们不仅需要将内存的一段代码同时也需要内存中的一块数据,一并传递给模块C。

那么如何实现上面的功能了? 你可以定义一个结构体,将代码和数据打包起来、

typedef void (*func) (int);

struct closure{
  func f;
  int arg;    
};

我们将这个结构体命名为 :closure 这个结构体中包含两部分

  1. 一个指向代码的指针变量
  2. 一个保存数据的变量 

这样,我们在模块A 为指针变量赋值,在模块B为保存数据的变量赋值,然后将此结构体传递给模块C ,模块C中可以这样使用。

void run(struct functor func) {
    func->f(func->arg);
}

closure既包含了一段代码也包含了这段代码使用的数据,这里的数据称为context (函数运行依赖的数据),这个技术就是:Functor 。(就是说:单纯的函数指针并没有捕捉上下文的能力,这里的上下文就是指代码依赖的数据,你不得不自己动手构造一个结构体用来存储代码依赖的上下文。)

 有的同学又会问了:为什么不用函数指针来指向对象的成员函数,这是因为函数指针没有办法捕捉 this (指向对象的指向) 这个上下文 。 (原因我后面在讲,这个不是本文的重点)

3:std::Function

  1. 所以 std::function的作用本质和我们刚刚定义的结构体区别不大。
  2. 利用std::function你不但可以保存一段代码,同时也可以保存必要的上下文,然后在合适的地方基于上下文调用这段代码。
  3. 同时std::function 更加通用,你可以用其存储任何可以被调用的对象(callable object)只要有正确的函数签名就可以了。

好像还是不能理解?没关系,我们一步一步带领大家去理解,大家先对 std::Function有一个概念性的认识。

3.1:先想一想:C++怎样定义指向对象成员函数的指针

参考我的这篇博文

C++:函数指针进阶二:指向对象成员函数的指针_hongwen_yul的博客-CSDN博客

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

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

相关文章

【季报分析】百度2022年Q3:逆势而上

11月22日&#xff0c;百度&#xff08;09888.HK&#xff09;发布了2022年第三季度的业绩报告&#xff0c;尽管面对疫情不断侵扰、外部环境压力带来的诸多挑战&#xff0c;百度在Q3依然取得了相当不错的财务数据&#xff0c;尤其是在自动驾驶、智能硬件方面的表现尤为突出&#…

【Linux】缓冲区

目录&#x1f308;前言&#x1f337;1、缓冲区&#x1f361;1.1、缓冲区的理解&#x1f362;1.2、缓冲区在哪里&#xff1f;&#x1f363;1.3、缓冲区的刷新策略&#x1f363;1.4、模拟实现C库函数&#x1f338;2、标准输出流与错误流的区别&#x1f364;2.1、概念&#x1f365…

微客云升级会员制度

会员制度 会员制度是一种人与人或组织与组织之间进行沟通的媒介&#xff0c;它是由某个组织发起并在该组织的管理运作下&#xff0c;吸引客户自愿加入&#xff0c;目的是定期与会员联系&#xff0c;为他们提供具有较高感知价值的利益包。 Part 1 会员制度 建立长期稳定的客…

Python测试框架之Pytest基础入门

Pytest简介 Pytest is a mature full-featured Python testing tool that helps you write better programs.The pytest framework makes it easy to write small tests, yet scales to support complex functional testing for applications and libraries. 通过官方网站介绍…

Vue子组件传自定义事件给父组件

我们知道组件之间是不能够进行通信的&#xff0c;都是相互独立的&#xff0c;你用不了我的状态和方法&#xff0c;我也用不了你的&#xff0c;那如何实现通信呢&#xff0c;可以间接实现&#xff1b; 实现父组件和子组件的通信&#xff1a; 子组件想用父组件的状态需要父组件…

Apache ShardingSphere(二) 基本使用

文章目录二 ShardingSphere JDBC 基本使用2.1 ShardingSphere JDBC 水平分表2.1.1 案例入门2.1.2 解读配置文件2.1.3 其他测试2.1.4 延伸问题2.2 ShardingSphere JDBC 水平分库2.2.1 案例入门2.2.2 解读配置文件2.1.3 其他测试2.3 ShardingSphere JDBC 广播表2.3.1 基本案例入门…

矩阵链相乘(动态规划)

【问题描述】给定n个矩阵M1,M2...MnM_1,M_2...M_nM1​,M2​...Mn​&#xff0c;他们的维数分别是r1∗c1,r2∗c2...rn∗cnr_1*c_1,r_2*c_2...r_n*c_nr1​∗c1​,r2​∗c2​...rn​∗cn​&#xff0c;要求使用【动态规划】的策略求解矩阵连乘的最优计算代价(总乘法次数最少)。题目…

Docker 学习视频集 bilibili

1.什么是Docker_哔哩哔哩_bilibili 2.Docker的安装_哔哩哔哩_bilibili 3.镜像、容器和仓库_哔哩哔哩_bilibili 4.在容器中部署一个应用_哔哩哔哩_bilibili 5.将容器保存成镜像成片_哔哩哔哩_bilibili 6.使用Dockerfile构建镜像1_哔哩哔哩_bilibili 7.导入导出镜像_哔哩哔…

vscode配合gitee同步云设置

更换开发设备后&#xff0c;新安装的vscode软件&#xff0c;是没有原先的配置的&#xff0c;诸如快捷键&#xff0c;快捷代码段生成、安装的各个插件&#xff0c;插件的配置等都木大了&#xff0c;开发起来会很别扭&#xff0c;网上最多的就是去安装一个叫做Settings Sync的插件…

springcloud五大核心部件

springcloud五大核心部件 一、springcloud介绍 springcloud是微服务的集大成者&#xff0c;将一系列的组件进行了整合。基于springboot构建 &#xff0c;可以快速配置常用模块并构建庞大的分布式系统。 二、具体业务分析 我们举一个例子来进行业务场景分析 假设现在开发一…

Websocket学习

参考&#xff1a;http://www.mydlq.club/article/86/ 这里写目录标题一、WebSocket 简介二、WebSocket 特点三、为什么需要 WebSocket四、WebSocket 连接流程五、WebSocket 使用场景六、使用案例1.提醒客户端有新订单2.客户端交互一、WebSocket 简介 WebSocket 是一种基于 TCP…

为什么越来越多的企业在会议室使用无线流媒体网关?

1&#xff0c;用户已有华为&#xff0c;MAXHUB等投屏功能设备&#xff0c;不需要这个设备了。但是市面上大部分投屏设备的使用存在以下问题&#xff1a; 操作麻烦&#xff0c;我们发射器是直接触摸投屏&#xff0c;安全性低&#xff0c;需要驱动软件。 2&#xff0c;市场上有很…

实现矩阵连乘积(动态规划)

目录 实现矩阵连乘积 题目 问题分析 算法分析 时间复杂度 代码实现 执行结果 动态规划 基本思想 举例 个人主页&#xff1a;天寒雨落的博客_CSDN博客-初学者入门C语言,python,数据库领域博主 &#x1f4ac; 热门专栏&#xff1a;初学者入门C语言_天寒雨落的博客-CSDN…

【SVM分类】基于鸽群算法优化支持向量机SVM实现分类附matlab的代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

arduino 复习题

名词解释 中断 计算机运行过程中&#xff0c;出现某些意外情况需主机干预时&#xff0c;机器能自动停止正在运行的程序并转入处理新情况的程序&#xff0c;处理完毕后又返回原被暂停的程序继续运行 中断服务程序 用于 CPU 处理中断的程序 中断源 引起中断的原因&#xff0c;或…

【JVS低代码平台】如何实现与外部系统/内部代码直接对接?

JVS是开放性的低代码开发平台&#xff0c;为开发团队预留了多种对接的方式。我这里列举集中对接的模式。 用户对接&#xff08;统一登录/单点跳转&#xff09; 在日常的企业需求中&#xff0c;常常有这种情况。企业内部考勤打开都是通过钉钉或者企微的&#xff0c;那么希望我们…

Grasp Detection论文、代码汇总

文章目录2022End-to-end Trainable Deep Neural Network for Robotic Grasp Detection and Semantic Segmentation from RGB2019Antipodal Robotic Grasping using Generative Residual Convolutional Neural Network2022 End-to-end Trainable Deep Neural Network for Robot…

现代PCB生产工艺——加成法、减成法与半加成法

继续为朋友们分享关于PCB生产工艺的知识。 现代PCB生产工艺&#xff0c;目前主要分为&#xff1a;加成法、减成法与半加成法。 其具体定义如下&#xff1a; 加成法&#xff1a; 通过网印或曝光形成图形&#xff0c;经钻孔、沉铜、转移层压等工艺加工&#xff0c;直接将导电图形…

Pycharm开发环境下创建python运行的虚拟环境(自动执行安装依赖包)

问题&#xff1a;基于Django开发的后台程序涉及到很多依赖的开发包&#xff0c;将该项目迁移到其它电脑环境下运行需要搭建环境&#xff0c;由于项目中有requirement.txt&#xff0c;该文件内包含了运行该项目所需的依赖&#xff1b;最简便的方式是执行命令自动安装requirement…

postgresql11 主从配置详解

以下内容是针对pgsql11来做的。请看好版本再去考虑是否往下看 准备两台服务器&#xff0c;地址如下&#xff1a; 主&#xff1a;192.168.0.1pgsql11从:192.168.0.2pgsql11一、主库配置 1、创建具有复制权限的用户replica 密码为000000 CREATE ROLE replica login replicat…