【C/C++】回调函数

news/2024/7/24 2:09:04 标签: c++, c语言, 开发语言

1. 概念

回调函数是一种在程序运行期间通过函数指针调用的函数,它通常用于实现事件驱动、异步通信、消息传递等功能

在回调函数的使用中,当某些事件发生时,系统会调用预先注册好的回调函数,将事件相关的数据传递给回调函数,由回调函数进行处理。这种回调函数的机制常用于异步通信、网络编程、GUI 前端等场景中,常见的回调函数包括事件处理函数、信号处理函数、消息处理函数等。

回调函数通常使用函数指针来进行实现,首先定义一个函数指针类型,然后将回调函数的地址赋值给函数指针,最后在需要注册回调函数的地方将函数指针作为参数传入即可。

在回调函数中,被调用的函数通常称为回调函数(Callback Function),而调用回调函数的函数通常称为回调函数容器(Callback Container)。回调函数容器可以在满足某些条件或事件发生时调用回调函数,以便执行相应的操作。

2. 用法举例

例如,假设有一个程序需要在读取文件完成后执行某些操作,可以将这些操作封装到一个回调函数中,并在文件读取完成后调用该回调函数。示例代码如下:

  • std::function 类型的回调函数
void readFromFile(const std::string& filename, std::function<void()> callback) {
  // 读取文件
  // ...

  // 文件读取完成后调用回调函数
  callback();
}

void onFileRead() {
  std::cout << "File read completed." << std::endl;
}

int main() {
  std::string filename = "example.txt";
  readFromFile(filename, onFileRead);
  return 0;
}

  • 函数指针模式的回调函数
typedef void (*CallbackFunction)();

void readFromFile(const std::string& filename, CallbackFunction callback) {
  // 读取文件
  // ...

  // 文件读取完成后调用回调函数
  callback();
}

void onFileRead() {
  std::cout << "File read completed." << std::endl;
}

int main() {
  std::string filename = "example.txt";
  CallbackFunction callback = &onFileRead;
  readFromFile(filename, callback);
  return 0;
}

3.总结

使用回调函数的好处是可以将程序的逻辑进行解耦,使得代码更加模块化和可扩展。通过传递不同的回调函数,可以在运行时定制程序的行为。在现代C++中,除了上述提到的几种方式外,还可以使用Lambda表达式和函数对象的operator()进行回调函数的实现。选择合适的方式取决于具体的需求和编码习惯。

4.其它补充

在C++中,回调函数是一种常见的编程模式,它允许将一个函数作为参数传递给另一个函数,以便在需要的时候进行调用。回调函数常用于事件处理、异步操作、状态通知等场景,提供了灵活的扩展和定制能力。

以下是在C++中实现回调函数的常见方式:

  1. 函数指针(Function Pointers):
    使用函数指针作为回调函数的一种传统方式。函数指针指向一个具体的函数,通过将函数指针作为参数传递给另一个函数,在需要的时候调用该函数指针。

示例:

#include <iostream>

void callbackFunction() {
    std::cout << "Callback function called." << std::endl;
}

void performTask(void (*callback)()) {
    // 执行任务...
    callback();  // 调用回调函数
    // 完成任务...
}

int main() {
    performTask(callbackFunction);
    return 0;
}

在上面的示例中,performTask函数接受一个函数指针callback作为参数,并在合适的时机调用该函数指针。

  1. 函数对象(Function Objects):
    使用函数对象作为回调函数的一种更灵活的方式。函数对象是重载了函数调用运算符operator()的类对象,通过将函数对象作为参数传递给另一个函数,可以在需要的时候调用该函数对象。

示例:

#include <iostream>

struct Callback {
    void operator()() const {
        std::cout << "Callback function called." << std::endl;
    }
};

void performTask(const Callback& callback) {
    // 执行任务...
    callback();  // 调用回调函数对象
    // 完成任务...
}

int main() {
    Callback callback;
    performTask(callback);
    return 0;
}

在上面的示例中,performTask函数接受一个函数对象callback作为参数,并在合适的时机调用该函数对象。

  1. std::function(C++11及以上):
    C++11引入的std::function提供了一种更为灵活和通用的回调函数机制。std::function是一个函数包装器,可以封装任意可调用对象(函数指针、函数对象、Lambda表达式等),并提供统一的调用接口。

示例:

#include <iostream>
#include <functional>

void callbackFunction() {
    std::cout << "Callback function called." << std::endl;
}

void performTask(const std::function<void()>& callback) {
    // 执行任务...
    callback();  // 调用回调函数
    // 完成任务...
}

int main() {
    performTask(callbackFunction);
    return 0;
}

在上面的示例中,performTask函数接受一个std::function对象callback作为参数,并在合适的时机调用该std::function对象。

使用回调函数的好处是可以将程序的逻辑进行解

耦,使得代码更加模块化和可扩展。通过传递不同的回调函数,可以在运行时定制程序的行为。在现代C++中,除了上述提到的几种方式外,还可以使用Lambda表达式和函数对象的operator()进行回调函数的实现。选择合适的方式取决于具体的需求和编码习惯。


http://www.niftyadmin.cn/n/420792.html

相关文章

BLIP和BLIP2

文章主要是对BLIP2 &#xff08;使用冻结图像编码器和大型语言模型的Bootstrapping语言图像预训练&#xff09;论文的阅读笔记&#xff0c;也对BLIP&#xff08;用于统一视觉语言理解和生成的Bootstrapping语言图像预训练&#xff09;算法进行了简单的介绍。 一、BLIP&#xf…

如何看待ICML2023的录用结果?

链接&#xff1a;https://www.zhihu.com/question/597314456 编辑&#xff1a;深度学习与计算机视觉 声明&#xff1a;仅做学术分享&#xff0c;侵删 作者&#xff1a;知乎用户 https://www.zhihu.com/question/597314456/answer/3000946712 不是因为文章被拒&#xff0c;而是因…

【网络原理】TCP/IP协议五层模型

&#x1f94a;作者&#xff1a;一只爱打拳的程序猿&#xff0c;Java领域新星创作者&#xff0c;CSDN、阿里云社区优质创作者。 &#x1f93c;专栏收录于&#xff1a;计算机网络原理 本期讲解协议、OSI七层模型、TCP/IP五层模型、网络设备所在的分层、数据的封装和分佣。 目录 …

【C/C++】函数指针

简介 如果在程序中定义了一个函数&#xff0c;那么在编译时系统就会为这个函数代码分配一段存储空间&#xff0c;这段存储空间的首地址称为这个函数的地址。而且函数名表示的就是这个地址。既然是地址我们就可以定义一个指针变量来存放&#xff0c;这个指针变量就叫作函数指针…

STM32CubeMX | 44 - 使用GPIO点亮单总线RGBLED

一、单总线RGBLED 1. 硬件连接 在DragonFly上有四个全彩灯相连: 其中RGB_LED连接到STM32的PB9引脚。 2. 单总线通信协议 单总线通信协议中,表示bit0和bit1的码型如下: 时序值如下: 驱动一个单总线RGBLED只需要传输24bit颜色数据即可(MSB,高位优先),格式如下(注意…

根据列表构造一棵树

List allMenus menuDao.findBy(“status”, Status.AVAILABLE.getKey(), “priority”, false); List rootMenu new ArrayList (); if (CollectionUtils.isNotEmpty(allMenus)) { Map<Long, Menu> menuMap new HashMap<Long, Menu>(); for (Menu menu : allMenu…

6.数据结构期末复习之查找和排序1

概念 静态查找: 无插入和删除 动态查找: 边插入删除边查找静态和动态查找的实现方式 1.线性表: 静态查 2.树表(二叉排序树)动态查 3.散列表 静态动态都可以查找: 集合中查找满足条件的数据关键码 1.主关键码:可以表标识数据唯一性 2.次关键码: 不能标识查找效率: 比较次数决定的…

27 getcwd 的调试

前言 同样是一个 很常用的 glibc 库函数 不管是 用户业务代码 还是 很多类库的代码, 基本上都会用到 获取当前路径 不过 我们这里是从 具体的实现 来看一下 测试用例 就是简单的使用了一下 getcwd rootubuntu:~/Desktop/linux/HelloWorld# cat Test04Getcwd.c #inc…