C++ 【回调函数】详解与代码解读

在现代软件开发中,回调函数是一个常用的工具,能够实现函数调用的延迟绑定,广泛应用于事件驱动、异步操作以及模块解耦等场景。本文将从基础概念、分类、实现方式到代码示例,全面讲解 C++ 回调函数的实现和应用。


什么是回调函数?

回调函数(Callback Function)是指一个函数通过函数指针或其他机制传递给另一个函数,在执行过程中由该函数调用。这种调用方式赋予了程序更大的灵活性,因为调用方无需知道具体的函数实现,只需在需要时触发回调。

一个生活中的例子

假设你使用外卖平台(一个函数)下单,平台会在订单完成后给你打电话(回调函数)。这个电话的内容可能是你指定的(动态绑定),但外卖平台不需要了解具体的细节,只负责在指定时间触发。


C++ 回调函数的分类

根据实现方式和场景,C++ 回调函数可以分为以下几类:

  1. 普通函数的回调

    • 通过函数指针实现,是最基础的回调方式。
  2. 类成员函数的回调

    • 普通成员函数:需要对象指针和成员函数指针配合使用。
    • 静态成员函数:可作为普通函数指针使用,简单灵活。
  3. 基于 std::functionstd::bind 的回调

    • 使用 C++11 引入的标准库实现,能够兼容普通函数、成员函数和 Lambda 表达式。
  4. Lambda 表达式的回调

    • C++11 引入的匿名函数机制,适用于简洁的回调逻辑。

实现回调函数的几种方式

1. 普通函数的回调

普通函数的回调是通过函数指针来实现的。函数指针保存了一个函数的地址,调用时可以直接跳转到该函数。

#include <iostream>
using namespace std;// 普通函数,作为回调函数
void callbackFunction(int value) {// 回调逻辑cout << "普通函数回调,被调用时传入的值是: " << value << endl;
}// 一个执行回调的函数
void executeCallback(void (*callback)(int), int value) {// 通过函数指针调用回调函数callback(value);
}int main() {// 将普通函数的地址(指针)传入executeCallback(callbackFunction, 42);return 0;
}
代码解析:
  1. callbackFunction 是普通函数,定义了回调的逻辑。
  2. executeCallback 是一个高阶函数,它接收函数指针 void (*callback)(int) 作为参数,并在内部调用回调函数。
  3. main 中,将函数 callbackFunction 的地址传递给 executeCallback,实现回调。
输出:
普通函数回调,被调用时传入的值是: 42

适用场景:适合简单的场景,例如小型工具程序。


2. 类成员函数的回调

由于普通成员函数必须依赖具体对象才能调用,因此在回调时需要传递对象指针和成员函数指针。

#include <iostream>
using namespace std;class CallbackHandler {
public:// 成员函数作为回调函数void memberCallback(int value) {cout << "成员函数回调,被调用时传入的值是: " << value << endl;}
};// 一个执行回调的函数
void executeMemberCallback(CallbackHandler* obj, void (CallbackHandler::*callback)(int), int value) {// 通过对象指针和成员函数指针调用成员函数(obj->*callback)(value);
}int main() {CallbackHandler handler; // 创建一个对象// 传递对象和成员函数指针进行回调executeMemberCallback(&handler, &CallbackHandler::memberCallback, 42);return 0;
}
代码解析:
  1. CallbackHandler 类中定义了一个成员函数 memberCallback
  2. executeMemberCallback 接收对象指针 CallbackHandler* obj 和成员函数指针 void (CallbackHandler::*callback)(int),通过 (obj->*callback)(value) 调用成员函数。
  3. main 函数中,通过对象 handler 和成员函数指针 &CallbackHandler::memberCallback 实现回调。
输出:
成员函数回调,被调用时传入的值是: 42

适用场景:适用于面向对象的程序,尤其是需要调用类成员函数的情况。


3. 基于 std::functionstd::bind 的回调

std::function 是现代 C++ 中推荐的工具,可以存储任意可调用对象(普通函数、成员函数、Lambda 表达式等),而 std::bind 可以绑定成员函数与对象。

#include <iostream>
#include <functional> // 包含 std::function 和 std::bind
using namespace std;// 一个执行回调的函数
void executeCallback(std::function<void(int)> callback, int value) {// 调用回调callback(value);
}void freeFunction(int value) {cout << "普通函数回调,被调用时传入的值是: " << value << endl;
}class CallbackHandler {
public:void memberCallback(int value) {cout << "成员函数回调,被调用时传入的值是: " << value << endl;}
};int main() {CallbackHandler handler;// 1. 传递普通函数作为回调executeCallback(freeFunction, 42);// 2. 传递 Lambda 表达式作为回调executeCallback([](int value) {cout << "Lambda 回调,被调用时传入的值是: " << value << endl;}, 43);// 3. 传递成员函数作为回调executeCallback(std::bind(&CallbackHandler::memberCallback, &handler, std::placeholders::_1), 44);return 0;
}
代码解析:
  1. std::function<void(int)> 可以存储普通函数、Lambda 表达式或绑定后的成员函数。
  2. 使用 std::bind 将成员函数和对象绑定,并通过 std::placeholders::_1 占位符传递参数。
输出:
普通函数回调,被调用时传入的值是: 42
Lambda 回调,被调用时传入的值是: 43
成员函数回调,被调用时传入的值是: 44

适用场景:适合复杂场景,尤其是需要兼容不同类型回调的情况。


4. Lambda 表达式的回调

Lambda 表达式是 C++11 引入的一种简洁的回调实现方式,适合定义小型的、一次性的回调逻辑。

#include <iostream>
using namespace std;// 一个执行回调的函数
void executeCallback(auto callback, int value) {callback(value);
}int main() {// 使用 Lambda 表达式定义回调executeCallback([](int value) {cout << "Lambda 表达式回调,被调用时传入的值是: " << value << endl;}, 42);return 0;
}
代码解析:
  1. Lambda 表达式是一种匿名函数,可以直接在需要的地方定义。
  2. 使用 auto 参数,避免显式定义函数类型。
输出:
Lambda 表达式回调,被调用时传入的值是: 42

适用场景:适用于简单的回调逻辑,代码更加简洁。


总结

实现方式优点缺点适用场景
普通函数的回调简单直观灵活性不足小型工具程序
类成员函数的回调面向对象,支持类的封装调用复杂,需要传递对象和函数指针面向对象程序
std::functionstd::bind强大灵活,支持多种可调用对象性能略低于直接函数指针复杂回调场景
Lambda 表达式的回调简洁直观,代码更加紧凑不适合复杂逻辑小型回调逻辑

在实际开发中,建议优先使用 Lambda 表达式std::function,它们在现代 C++ 编程中更易读、易维护,同时具有更好的兼容性。

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

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

相关文章

嵌入式开发之使用 FileZilla 在 Windows 和 Ubuntu 之间传文件

01-FileZilla简介 FileZilla 是一个常用的文件传输工具&#xff0c;它支持多种文件传输协议&#xff0c;包括以下主要协议&#xff1a; FTP (File Transfer Protocol) 这是 FileZilla 最基本支持的协议。FTP 是一种明文传输协议&#xff0c;不加密数据&#xff08;包括用户名和…

IDEA XML 文件 SQL 提示

首先连接到对应的数据库。Database 里面要填写对应的数据库名称 配置当前项目的 SQL 方言&#xff0c;例如我这里是 MySQL 数据库管理系统&#xff0c;那么就选择 MySQL 此时就有 SQL 语法、表名、字段名等提示信息了

SSA-Transformer拿捏!麻雀搜索算法优化-Transformer多特征分类预测/故障诊断

SSA-Transformer拿捏&#xff01;麻雀搜索算法优化-Transformer多特征分类预测/故障诊断 目录 SSA-Transformer拿捏&#xff01;麻雀搜索算法优化-Transformer多特征分类预测/故障诊断效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现SSA-Transformer麻雀搜索…

PaddleOCROCR关键信息抽取训练过程

步骤1&#xff1a;python版本3.8.20 步骤2&#xff1a;下载代码&#xff0c;安装依赖 git clone https://gitee.com/PaddlePaddle/PaddleOCR.git pip uninstall opencv-python -y # 安装PaddleOCR的依赖 ! pip install -r requirements.txt # 安装关键信息抽取任务的依赖 !…

SimForge HSF 案例分享|复杂仿真应用定制——UAVSim无人机仿真APP(技术篇)

导读 「神工坊」核心技术——「SimForge HSF高性能数值模拟引擎」支持工程计算应用的快速开发、自动并行&#xff0c;以及多域耦合、AI求解加速&#xff0c;目前已实现航发整机数值模拟等多个系统级高保真数值模拟应用落地&#xff0c;支持10亿阶、100w核心量级的高效求解。其低…

A3C算法在超级马里奥实战中的应用研究

源码地址见文末 摘要 在深度学习和人工智能领域,强化学习技术的应用正不断推动着机器智能的边界。超级马里奥(Super Mario)作为一款经典的电子游戏,因其复杂的动态环境和多样化的游戏任务,成为深度强化学习的重要测试平台。本文以A3C(Asynchronous Advantage Actor-Crit…

聊天机器人Rasa面试内容整理-Rasa 是什么?

Rasa 是一个开源的框架,专门用于构建对话式 AI 应用程序,例如聊天机器人和语音助手。它由两部分组成:Rasa Open Source 和 Rasa Pro (或 Rasa Enterprise),提供了强大的工具集来创建自然语言理解(NLU)和对话管理(DM)功能。 Rasa 的主要特点 1. 自然语言理解(NLU): …

bev and occupancy 3D视觉工坊

纯激光雷达的占据预测数据集制作 Allan 方差&#xff0c;零漂&#xff0c;把imu静止在一个地方&#xff0c;看它的偏差 评估指标 waymo

ts总结一下

ts基础应用 /*** 泛型工具类型*/ interface IProps {id: string;title: string;children: number[]; } type omita Omit<IProps, id | title>; const omitaA: omita {children: [1] }; type picka Pick<IProps, id | title>; const pickaA: picka {id: ,title…

【分布式文件存储系统Minio】2024.12保姆级教程

文章目录 1.介绍1.分布式文件系统2.基本概念 2.环境搭建1.访问网址2.账号密码都是minioadmin3.创建一个桶4.**Docker安装miniomc突破7天限制**1.拉取镜像2.运行容器3.进行配置1.格式2.具体配置 4.查看桶5.给桶开放权限 3.搭建minio模块1.创建一个oss模块1.在sun-common下创建2.…

udp分片报文发送和接收

读文件通过udp分片发送的目的端&#xff1a;&#xff08;包含错误的分片包&#xff09; #!/usr/bin/python # -*- coding: utf-8 -*-#python send_100frag_file.py -p 55432 -f snatdownloadimport argparse import loggingfrom scapy.all import *# Define the maximum size …

好用的随机生成图片的网站

官网&#xff1a; Lorem Picsum 获取自定义大小的随机图像 https://picsum.photos/200/300 获取正方形图像 https://picsum.photos/200 获取特定类型的图像 通过添加到 /id/{image} url 的开头来获取特定图像。 https://picsum.photos/id/237/200/300 获取静态随机图像…

2024-12-31-devkit-pipeline

title: 解析 Devkit-Pipeline&#xff1a;开发流程自动化的新动力 date: ‘2024-12-31’ category: blog tags: Devkit-Pipeline开发流程自动化持续集成软件开发效率 sig: CICD archives: ‘2024-12’ author:way_back summary: Devkit-Pipeline 是一款为软件开发流程带来高效…

“进制转换”公式大集合

咱们都知道十进制是“逢10进1 ”&#xff0c;同理&#xff0c;N进制就是 “逢N进1”。进制其实就这么简单。它的麻烦之处在于各种进制之间的转换。 一、十进制整数转N进制 1&#xff0e;十进制转二进制 除2取余法&#xff1a;连续除以2&#xff0c;直到商为0&#xff0c;逆序…

解决k8s部署dashboard时一直处于Pending状态的问题

直接用离线包就行 命令 [rootk8s-master ~]# docker load -i calico-image-v3.25.0.tar [rootk8s-master ~]# kubectl apply -f calico.yaml链接在https://download.csdn.net/download/weixin_42759398/90192045 [rootk8s-master ~]# docker load -i calico-image-v3.25.0.t…

在计算机网络中,什么是集群?

在计算机网络中&#xff0c;集群&#xff08;Cluster&#xff09;指的是一组相互独立的计算机&#xff08;也称为节点&#xff09;&#xff0c;它们通过高速通信网络互联&#xff0c;共同协作以提供高性能、高可用性和可扩展性的计算资源和服务。这些计算机在逻辑上被组织成一个…

【视觉SLAM:八、后端Ⅰ】

视觉SLAM的后端主要解决状态估计问题&#xff0c;它是优化相机轨迹和地图点的过程&#xff0c;从数学上看属于非线性优化问题。后端的目标是结合传感器数据&#xff0c;通过最优估计获取系统的状态&#xff08;包括相机位姿和场景结构&#xff09;&#xff0c;在状态估计过程中…

Vue.js前端框架教程15:Vue父子组件之间的通信ref、emits

文章目录 1. 属性传递(Props)2. 事件监听( Emits)3. `ref` 引用4. `provide` 和 `inject`5. 插槽(Slots)在 Vue 3 中,父子组件之间的通信可以通过多种方式实现,包括属性传递、事件监听、插槽以及 ref 和 provide/inject。以下是这些通信方式的详解: 1. 属性传递(Pro…

SpringCloudAlibaba实战入门之路由网关Gateway过滤器(十三)

承接上篇,我们知道除了断言,还有一个重要的功能是过滤器,本节课我们就讲一下常见的网关过滤器及其一般使用。 一、Filter介绍 类似SpringMVC里面的的拦截器Interceptor,Servlet的过滤器。“pre”和“post”分别会在请求被执行前调用和被执行后调用,用来修改请求和响应信…

[C#]C# random.Next(0,1)包含0和1吗

在C#中&#xff0c;Random.Next(minValue, maxValue) 方法生成的随机数是一个在 minValue&#xff08;包含&#xff09;和 maxValue&#xff08;不包含&#xff09;之间的整数。因此&#xff0c;当你调用 Random.Next(0, 1) 时&#xff0c;它只会生成一个整数&#xff0c;这个整…