C++回调函数

news2024/11/19 13:28:05

回调函数

文章目录

  • 回调函数
    • 一、函数指针
    • 二、回调函数
    • 应用
    • Reference

一、函数指针

指针是一个变量,是用来指向内存地址。

一个程序运行时,所有和运行相关的东西都需要加载到内存当中,因此可以通过指针指向该内存。

函数是存放在内存代码区域内的,函数名就是函数地址,把这种指向函数入口地址的指针称为函数指针。

Example:

#include <iostream>

typedef int (*fp)(int, int);

int Sum(int lhs, int rhs) {
  return lhs + rhs;
}

int Minus(int lhs, int rhs) {
    return lhs - rhs;
}

int main() {
  int (*randy)(int, int);
  randy = Sum;
  std::cout << randy(2, 13) << std::endl;  // 输出:15

  fp sesame = Minus;
  std::cout << sesame(22, 1) << std::endl;  // 输出:21
  return 0;
}

可以通过 typedef 的方式简化操作 typedef int (*fp)(int, int); ,也可以直接定义一个函数指针 int (*randy)(int, int);

二、回调函数

当我们把指针作为函数参数时,可以获取该指针所对应的那块内存。

如果这个指针是函数指针,就可以调用该函数的方法进行处理,这个被调用的具体处理的函数就是回调函数。

从上面的例子可以看出来,同一个函数指针,可以指向不同的函数实现,因此可以针对不同的场景,传入不同的函数,而调用方根本不用修改代码。

这就是回调函数灵活的地方,调用者根本不用关注函数如何实现的,只需要关注何时调用即可。

回调函数的使用方法:

  • 定义一个回调函数;

  • 调用者在使用时,保存回调函数的函数指针,称为“注册”;

  • 调用者发现条件满足时,使用函数指针调用回调函数对事件进行处理。

  • 回调可用于通知机制。比如要写一个多线程下载器,显示下载进度时可以将进度值函数设置为函数,线程内部即可处理,非常方便。

回调函数是继承自C语言的。一般C语言没有多态,所以通过设置回调函数或者钩子函数,达到同样的函数调用不同实现函数的目的。

应用

带参回调函数:

#include <iostream>

// 定义带参回调函数
int callbackFun(int lhs, int rhs) {
	return lhs + rhs;
}

// 定义参数为回调函数的"调用函数"
int callbackRandy(int (*fp)(int, int), int lhs, int rhs) {
	return fp(lhs, rhs);
}

int main() {
	// 运行时执行"调用函数",调用回调函数callbackFun
	int sum = callbackRandy(callbackFun, 2, 13);
	std::cout << sum << std::endl; // 输出:3

	return 0;
}

类的静态成员函数和非静态成员函数

#include <iostream>

class Randy {
 public:
  void R1_Non_Static() { 
    std::cout << "call function R1_Non_Static" << std::endl;
  }

  static void R2_Static() {
    std::cout << "call function R2_Static" << std::endl;
   }
};

class Sesame {
 public:
  void Ses_call1(void (*callBack)()) {
    std::cout << "call function Ses_call1" << std::endl;
    callBack();
  }

  void Ses_call2(void (Randy::*callBack)(), void *object) {
    std::cout << "call function Ses_call2" << std::endl;
    ((Randy *)object->*callBack)();
  }
};

int main(int argc, char **argv) {
  Randy randy;

  Sesame sesame;
  sesame.Ses_call2(&Randy::R1_Non_Static, &randy);
  sesame.Ses_call1(Randy::R2_Static);
}

结果:

call function Ses_call2
call function R1_Non_Static
call function Ses_call1
call function R2_Static

上面Ses_call2有个缺陷,就是实现里调用了Randy类,鲁棒性不强,因此可以增加1层包装:

#include <iostream>

class Randy {
 public:
  void R1_Non_Static() { 
    std::cout << "call function R1_Non_Static" << std::endl;
  }

  static void R2_Static() {
    std::cout << "call function R2_Static" << std::endl;
   }

    // 包装函数
   static void Wrapper(void *objectR) {
    std::cout << "call function Wrapper" << std::endl;
    reinterpret_cast<Randy *>(objectR)->R1_Non_Static();
   }
};

class Sesame {
 public:
  void Ses_call1(void (*callBack)()) {
    std::cout << "call function Ses_call1" << std::endl;
    callBack();
  }

  void Ses_call2(void (Randy::*callBack)(), void *object) {
    std::cout << "call function Ses_call2" << std::endl;
    ((Randy *)object->*callBack)();
  }

   // 针对包装函数的调用
  void Ses_call3(void (*callBack)(void *), void *objectS) {
    std::cout << "call function Ses_call3" << std::endl;
    callBack(objectS);
  }
};

int main(int argc, char **argv) {
  Randy randy;

  Sesame sesame;
  sesame.Ses_call2(&Randy::R1_Non_Static, &randy);
  sesame.Ses_call1(Randy::R2_Static);
  sesame.Ses_call3(&Randy::Wrapper, &randy);
}

运行结果:

call function Ses_call2
call function R1_Non_Static
call function Ses_call1
call function R2_Static
call function Ses_call3
call function Wrapper
call function R1_Non_Static

Reference

  • 关于C++ 回调函数(callback) 精简且实用
  • 【C++11 回调函数】回调入门(一)

欢迎关注公众号【三戒纪元】

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

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

相关文章

Otter CTF--Network(web网络1-3)

目录 一.题目 1.Birdmans Data 2.Look At Me 3.Otter Leak 一.题目 网址 OtterCTF 1.Birdmans Data 下载文件&#xff1a; .pcap文件 Wireshark打开&#xff1a; 既然是web 我们就从http分析&#xff1a; 追踪流 HTTP流&#xff1a; 发现两个密钥key&#xff1a; {"…

数据集 | 基于语音(Speech)/多模态(Multimodal)的情绪识别数据集,格式及下载

本文主要介绍了一些常用的语音&#x1f5e3;识别数据集&#xff0c;文件格式以及下载地址&#xff1a; 目录 1.IEMOCAP Emotion Speech Database(English) 2.Emo-DB Database(German) 文件命名 对象 3.Ryerson Audio-Visual Database of Emotional Speech and Song (Engli…

解密JS代码:一个有趣的故事

作为一名前端开发者&#xff0c;我们经常需要处理加密和解密的任务。近日&#xff0c;我遇到了一个有趣的故事和一个需要解密的JavaScript代码。让我和你分享一下这个故事以及我是如何解密这段代码的。 最近我收到了一个任务&#xff0c;要将一个网站上的一段JavaScript代码进…

torch_geometric获取datasets(解决连不了外网的问题)

文章目录 1. torch_geometric.data介绍2. 使用Planetoid下载Cora数据集的代码3. 解决程序运行的机器无法联网的问题3.1 尝试运行&#xff0c;查看数据集下载链接3.2 放置到对应文件夹下3.3 重新运行之前写的程序 4. 一点感慨 1. torch_geometric.data介绍 torch_geometric&…

进货商模式玩法解析:当老板、亲自进货、自己赚差价?

如今很多人都看到互联网的发展前景&#xff0c;有了创业的想法&#xff0c;但是资金、技术、市场等问题给他们带来了瓶颈。进货商模式的出现&#xff0c;为这些&#xff08;文章编辑ycy6221&#xff09;有创业想法&#xff0c;有梦想的人打破了这些限制&#xff0c;而且还可以实…

HTTP协议演进:为什么说HTTP/1.1的时代已经过去了

前言 欢迎来到今天的每日一题&#xff0c;每日一提。昨天聊到了&#xff0c;HTTP 是什么。有哪些组成部分。并且最后提到了 HTTP 的一些缺点&#xff0c;比如&#xff1a;性能较低&#xff0c;容易导致网络拥塞和延迟&#xff0c;不支持服务器推送等等。设计协议的大佬们&#…

ChatGPT实现安全漏洞检查

安全漏洞检查 几乎每一项新技术的出现&#xff0c;都会首先被运用在安全领域&#xff0c;ChatGPT 也不例外。在 ChatGPT 出现的第一时间&#xff0c;利用 ChatGPT 编写钓鱼邮件&#xff0c;进行社会工程学攻击&#xff0c;辅助分析代码漏洞等等就成为热门话题。其实技术只是工…

快速上手Vite 配置指南

&#x1f482; 个人网站:【紫陌】【笔记分享网】 &#x1f485; 想寻找共同学习交流、共同成长的伙伴&#xff0c;请点击【前端学习交流群】 文章最后有作者l联系方式&#xff08;备注进群&#xff09; 1.认识vite 什么是vite呢&#xff1f; 官方的定位&#xff1a;下一代前端…

《水经注地图服务》数据源说明

&#xff08;本文首发于“水经注GIS”公号&#xff0c;关注公号免费领取地图数据&#xff09; 《水经注地图服务》&#xff08;WeServer&#xff09;是一款可快速发布全国乃至全球海量卫星影像的地图发布服务产品&#xff0c;该产品完全遵循OGC相关协议标准&#xff0c;是一个…

老板给情人转166万,妻子起诉后追回,网友:这是被白嫖三年

作为一个已婚男人&#xff0c;戚某在婚姻关系中背离了对妻子的忠诚&#xff0c;与小自己14岁的女员工小汪发展出不正当的男女关系。而小汪&#xff0c;在明知对方已婚的情况下&#xff0c;仍然选择继续纠缠&#xff0c;最终付出了惨痛的代价。 据了解&#xff0c;戚某在上海经营…

会议签到二维码制作教程

纸质签到表、人工逐一核对等传统的会议签到方式&#xff0c;存在着耗时耗力、容易出错、不环保等种种弊端。 可以制作一个包含签到表单的签到二维码&#xff0c;参会人员使用微信扫码签到&#xff0c;自动授权填写手机号、定位等信息&#xff0c;管理人员在小程序以及电脑端实…

【团购-自己实现代理 Objective-C语言】

一、我们上节课,实现了数据加载,下面是不是有个加载更多啊, 1.我们先把这个“加载更多”给大家做一下, 这个加载更多,注意看,因为这个加载更多,是显示在UITableView的最底部的, 它会随着UITableView一起滚动吧, 证明,它是在UITableView的tableFooterView里面显示的…

Linux系统中tar.gz与rpm结尾的文件在安装程序时究竟有什么不同?

tar.gz tar.gz就是一个压缩包&#xff01; 使用的时候需要使用tar命令配上一些参数来进行解压。 关于tar的使用&#xff0c;大家可以参考这篇博客&#xff0c;这位大佬写的很详细。 Linux tar命令详解 在解压完后&#xff0c;这就是一个独立的文件&#xff0c;里面包含着关…

第十五章_Redis与MySQL数据双写一致性工程落地案例

复习面试题 采用双检加锁策略 多个线程同时去查询数据库的这条数据&#xff0c;那么我们可以在第一个查询数据的请求上使用一个 互斥锁来锁住它。 其他的线程走到这一步拿不到锁就等着&#xff0c;等第一个线程查询到了数据&#xff0c;然后做缓存。 后面的线程进来发现已经…

Redis内幕揭秘:探索Redis基础知识及应用场景,挖掘出高效的缓存技术

Redis 是一个开源的内存数据结构存储系统&#xff0c;它可以用作数据库、缓存和消息中间件。以下是 Redis 的发展史&#xff1a; 2009 年&#xff1a;Salvatore Sanfilippo 开始编写 Redis。2010 年&#xff1a;Redis 发布了 1.0 版本。这个版本包含了许多常用的数据结构&…

在陌生人社交场景 挖呀挖呀挖……

在陌生人社交场景 挖呀挖呀挖&#xff0c; 找可靠的大品牌&#xff08;网易&#xff09;&#xff0c;享最优惠的价~ &#x1f604; 对于“深挖”娱乐社交领域需求的开发者来说&#xff0c;陌生人社交是毋庸置疑最受青睐的场景。尤其是对渴望交流、敢于表达自我的年轻人来说&…

10-HTML-表单标签

标签描述<form>定义供用户输入的 HTML 表单。<input>定义输入控件。<textarea>定义多行的文本输入控件。<button>定义按钮。<select>定义选择列表&#xff08;下拉列表&#xff09;。<optgroup>定义选择列表中相关选项的组合。<option&…

【Rust日报】2023-05-10 llm - 使用Rust在CPU上运行大模型

llm - 使用Rust在CPU上运行大模型 这是一套工具。目前支持这些模型&#xff1a; GPT-2GPT-JLLaMA: LLaMA, Alpaca, Vicuna, Koala, GPT4All v1, GPT4-X, WizardGPT-NeoX: GPT-NeoX, StableLM, Dolly v2 (partial, not the same tensor names?)BLOOM: BLOOMZ https://github.co…

多优先级(笔记)

目录 支持多优先级的方法通用方法优化方法1、修改任务控制块2、修改xTaskCerateStactic()修改 prvInitialiseNewTask() 函数prvAddTaskToReadyList()初始化任务列表prvAddTaskToReadyList()vTaskStartScheduler()vTaskDelay()vTaskSwitchContext()xTaskIncrementTick() 实验实验…

如何成就一个伟大的公司?

任何事物都不及“伟大”那样简单&#xff0c;事实上&#xff0c;能够“简单”便是伟大。最优秀的模式&#xff0c;往往是最简单的东西。 那么&#xff0c;如今作为一名创业者&#xff0c;要如何才能更好的发展自己的公司&#xff0c;把带领的团队打造成为一个伟大的公司呢&…