C/C++回調函數實現與std::function和std::bind介紹

1 概述

  • 回調函數是一種編程模式,指的是將一個函數作為參數傳遞給另一個函數,并在某個特定事件發生時或滿足某些條件時由該函數調用。
  • 這種機制允許你定義在特定事件發生時應執行的代碼,從而實現更靈活和模塊化的程序設計。

2 傳統C/C++回調實現方式

  • 傳統C/C++實現回調,主要通過函數指針來實現。
  • 有這樣一個場景,某業務系統需要檢測環境溫度,當溫度大于50度時進行告警,告警接口就可以作為回調函數,在溫度大于50度時調用。這里通過隨機生成一個溫度值,模式現實場景。
  • 示例
    •   #include <iostream>#include <stdlib.h>#include <time.h>// 定義函數指針typedef void(*pCb)(int);void BusProcess(int tempera, pCb cb) {printf("開始業務\n");printf("業務處理中\n");// 處理業務過程中,如果溫度值大于50攝氏度,則調用告警接口進行告警if (tempera > 50) {cb(tempera);}printf("結束業務\n");}// 定義回調函數void temWarning(int tempera) {printf("溫度值為: %d 已超閾值,告警 ...\n", tempera);}int main() {{srand(time(NULL));  // 隨機生成溫度值int tempera = rand() % 100;// 開啟業務BusProcess(tempera, temWarning);}system("pause");return 0;}
      
  • 打印結果
    •   開始業務業務處理中溫度值為: 65 已超閾值,告警 ...結束業務請按任意鍵繼續. . .
      

3 C++11提供的回調新實現方式

  • 介紹C++11實現回調前先介紹C++11提供的兩個新接口std::functionstd::bind

3.1 std::function

  • std::function是一個通用的函數包裝器,可以存儲任何可調用對象,包括普通函數、類成員函數、仿函數、Lambda表示式。
  • 基本語法
    •   #include <functional>std::function<返回值類型(參數類型列表)> 函數對象;
      
  • 示例
    •   #include <iostream>#include <functional>// 普通函數int add(int a, int b) {return a + b;}class Multiply {public:int operator()(int a, int b) {return a * b;}};int main() {// 存儲普通函數std::function<int(int, int)> func1 = add;std::cout << "func1 result: " << func1(3, 4) << std::endl;// 存儲 Lambda 表達式std::function<int(int, int)> func2 = [](int a, int b) { return a - b; };std::cout << "func2 result: " << func2(10, 3) << std::endl;// 存儲函數對象Multiply multiply;std::function<int(int, int)> func3 = multiply;std::cout << "func3 result: " << func3(5, 6) << std::endl;return 0;}
      

3.2 std::bind

  • std::bind是一個函數模板,用于將函數或成員函數與其參數綁定,生成一個新的可調用對象。
  • 基本語法
    •   // 綁定非類成員函數/變量auto f = std::bind(可調用對象地址, 綁定的參數/占位符);// 綁定類成員函/變量auto f = std::bind(類函數/成員地址, 類實例對象地址, 綁定的參數/占位符);
      
  • 示例
    •   #include <iostream>#include <functional>int add(int a, int b) {return a + b;}class MyClass {public:int multiply(int a, int b) {return a * b;}};int main() {// 綁定普通函數auto boundAdd = std::bind(add, std::placeholders::_1, std::placeholders::_2);std::cout << "Result: " << boundAdd(5, 10) << std::endl; // 輸出 15MyClass obj;// 綁定類成員函數auto boundMultiply = std::bind(&MyClass::multiply, &obj, std::placeholders::_1, std::placeholders::_2);std::cout << "Result: " << boundMultiply(3, 4) << std::endl; // 輸出 12system("pause");return 0;}
      

3.3 C++11實現回調

  • 介紹完std::functionstd::bind再看下如何使用C++11語法實現回調。

  • 回調函數為普通函數時示例

    •   #include <iostream>#include <stdlib.h>#include <time.h>#include <functional>void BusProcess(int tempera, std::function<void(int)> op) {printf("開始業務\n");printf("業務處理中\n");// 處理業務過程中,如果溫度值大于50攝氏度,則調用告警接口進行告警if (tempera > 50) {op(tempera);}printf("結束業務\n");}void temWarning(int tempera) {printf("溫度值為: %d 已超閾值,告警 ...\n", tempera);}int main() {{srand(time(NULL));  // 隨機生成溫度值int tempera = rand() % 100;// 開啟業務,調用對象為普通函數BusProcess(tempera, temWarning);}system("pause");return 0;}
      
  • 打印結果

    •   開始業務業務處理中溫度值為: 56 已超閾值,告警 ...結束業務請按任意鍵繼續. . .
      
  • 回調函數為類成員對象、函數對象、Lambda時示例

    •   #include <iostream>#include <stdlib.h>#include <time.h>#include <functional>void BusProcess(int tempera, std::function<void(int)> op) {printf("開始業務\n");printf("業務處理中\n");// 處理業務過程中,如果溫度值大于50攝氏度,則調用告警接口進行告警if (tempera > 50) {op(tempera);}printf("結束業務\n");}class MyWarn {public:void startWarning(int tempera) {printf("溫度值為: %d 已超閾值,告警 ...\n", tempera);}void operator()(int tempera) {printf("operator() 溫度值為: %d 已超閾值,告警 ...\n", tempera);}};int main() {{srand(time(NULL));// 隨機生成溫度值int tempera = rand() % 100;MyWarn mwarn;std::function<void(int)> fc = std::bind(&MyWarn::startWarning, &mwarn, std::placeholders::_1);// 調用對象為類成員函數BusProcess(tempera, fc);MyWarn mwarn2;std::function<void(int)> fc2 = mwarn2;// 調用對象為仿函數BusProcess(tempera, fc2);// 調用對象為Lambda表達式BusProcess(tempera, [](int te) {printf("Lambda 溫度值為: %d 已超閾值,告警 ...\n", te);});}system("pause");return 0;}
      
  • 打印結果

    •   開始業務業務處理中溫度值為: 66 已超閾值,告警 ...結束業務開始業務業務處理中operator() 溫度值為: 66 已超閾值,告警 ...結束業務開始業務業務處理中Lambda 溫度值為: 66 已超閾值,告警 ...結束業務請按任意鍵繼續. . .
      
  • class MyWarn {public:void startWarning(int tempera) {printf("溫度值為: %d 已超閾值,告警 ...\n", tempera);}};#include <iostream>#include <string>#include <vector>#include <stdlib.h>#include <time.h>#include <functional>class myPersion {public:myPersion(): mCode(1001), mName("Jack") {}void setCode(int code) {std::cout << "code: " << code << std::endl;mCode = code;}private:int mCode;std::string mName;};typedef void(*pCb)(int);void optFunc(int data, pCb cb) {printf("optFunc ...\n");if (data % 2 == 0) {cb(data);}}void optFunc2(int data, std::function<void(int)> op) {printf("optFunc2 ...\n");if (data % 2 == 0) {op(data);}}void onHandle(int data) {printf("onHandle ...\n");}int main() {{srand(time(NULL));  // 初始化隨機數生成器int radNum = rand() % 100;printf("radNum: %d\n", radNum);optFunc(radNum, onHandle);myPersion mp;//optFunc(1001, &mp.setCode);}{srand(time(NULL));  // 初始化隨機數生成器int radNum = rand() % 100;printf("radNum: %d\n", radNum);optFunc2(radNum, onHandle);optFunc2(radNum, [](int x) {printf("lam ...\n");});myPersion mp;std::function<void(int)> fc = std::bind(&myPersion::setCode, &mp, std::placeholders::_1);optFunc2(10010, fc);}system("pause");return 0;}
    

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/75306.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/75306.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/75306.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【藍橋杯】單片機設計與開發,速成備賽

一、LED模塊開看&#xff0c;到大模板 二、刷第零講題目&#xff08;直接復制模板&#xff09; 三、空降芯片模板直接調用部分&#xff08;聽完再敲代碼&#xff09; 四、第十三講開刷省賽題&#xff08;開始自己背敲模板&#xff09; 五、考前串講刷一遍 b連接&#xff1…

Java 基礎-28- 多態 — 多態下的類型轉換問題

在 Java 中&#xff0c;多態&#xff08;Polymorphism&#xff09;是面向對象編程的核心概念之一。多態允許不同類型的對象通過相同的方法接口進行操作&#xff0c;而實際調用的行為取決于對象的實際類型。雖然多態提供了極大的靈活性&#xff0c;但在多態的使用過程中&#xf…

Epub轉PDF軟件Calibre電子書管理軟件

Epub轉PDF軟件&#xff1a;Calibre電子書管理軟件 https://download.csdn.net/download/hu5566798/90549599 一款好用的電子書管理軟件&#xff0c;可快速導入電腦里的電子書并進行管理&#xff0c;支持多種格式&#xff0c;閱讀起來非常方便。同時也有電子書格式轉換功能。 …

在 Ubuntu 22.04 上安裝 Docker Compose 的步驟

1. 確保已安裝 Docker Docker Compose 需要 Docker 作為依賴&#xff0c;請先安裝 Docker&#xff1a; sudo apt update sudo apt install docker.io sudo systemctl enable --now docker2. 下載 Docker Compose 二進制文件 推薦安裝最新穩定版的 Docker Compose&#xff08…

Mysql-數據庫、安裝、登錄

一. 數據庫 1. 數據庫&#xff1a;DataBase&#xff08;DB&#xff09;&#xff0c;是存儲和管理數據的倉庫。 2. 數據庫管理系統&#xff1a;DataBase Management System&#xff08;DBMS&#xff09;,操縱管理數據庫的大型軟件 3. SQL&#xff1a;Structured Query Language&…

基于SpringAOP面向切面編程的一些實踐(日志記錄、權限控制、統一異常處理)

前言 Spring框架中的AOP&#xff08;面向切面編程&#xff09; 通過上面的文章我們了解到了AOP面向切面編程的思想&#xff0c;接下來通過一些實踐&#xff0c;去更加深入的了解我們所學到的知識。 簡單回顧一下AOP的常見應用場景 日志記錄&#xff1a;記錄方法入參、返回值、執…

Rust 語言語法糖深度解析:優雅背后的編譯器魔法

之前介紹了語法糖的基本概念和在C/Python/JavaScript中的使用&#xff0c;今天和大家討論語法糖在Rust中的表現形式。 程序語言中的語法糖&#xff1a;讓代碼更優雅的甜味劑 引言&#xff1a;語法糖的本質與價值 語法糖(Syntactic Sugar) 是編程語言中那些并不引入新功能&…

【56】數組指針:指針穿梭數組間

【56】數組指針&#xff1a;指針穿梭數組間 引言 在嵌入式系統開發中&#xff0c;指針操作是優化內存管理和數據交互的核心技術。本文以STC89C52單片機為平臺&#xff0c;通過一維指針強制轉換、二維指針結構化操作和**return返回指針**三種方法&#xff0c;系統講解指針操作二…

C語言【指針二】

引言 介紹&#xff1a;const修飾指針&#xff0c;野指針 應用&#xff1a;指針的使用&#xff08;strlen的模擬實現&#xff09;&#xff0c;傳值調用和傳指調用 一、const修飾指針 1.const修飾變量 簡單回顧一下前面學過的const修飾變量&#xff1a;在變量前面加上const&…

學習記錄-軟件測試基礎

一、軟件測試分類 1.按階段&#xff1a;單元測試&#xff08;一般開發自測&#xff09;、集成測試、系統測試、驗收測試 2.按代碼可見度測試&#xff1a;黑盒測試、灰盒測試、白盒測試 3.其他&#xff1a;冒煙測試(冒煙測試主要是在開發提測后進行&#xff0c;主要是測試主流…

RAG系統實戰:當檢索為空時,如何實現生成模塊的優雅降級(Fallback)?

目錄 RAG系統實戰&#xff1a;當檢索為空時&#xff0c;如何實現生成模塊的優雅降級&#xff08;Fallback&#xff09;&#xff1f; 一、為什么需要優雅降級&#xff08;Fallback&#xff09;&#xff1f; 二、常用的優雅降級策略 策略一&#xff1a;預設后備提示&#xff0…

spring boot前后端開發上傳文件時報413(Request Entity Too Large)錯誤的可能原因及解決方案

可能原因及解決方案 1. Spring Boot默認文件大小限制 原因&#xff1a;Spring Boot默認單文件最大為1MB&#xff0c;總請求體限制為10MB。解決方案&#xff1a; 在application.properties中配置&#xff1a;spring.servlet.multipart.max-file-size10MB # 單文件最大 spring…

Qt - findChild

findChild 1. 函數原型2. 功能描述3. 使用場景4. 示例代碼5. 注意事項6. 總結 在 Qt 中&#xff0c;每個 QObject 都可以擁有子對象&#xff0c;而 QObject 提供的模板函數 findChild 就是用來在對象樹中查找滿足特定條件的子對象的工具。下面我們詳細介紹一下它的使用和注意事…

Sink Token

論文&#xff1a;ICLR 2025 MLLM視覺VAR方法Attention重分配 Sink Token 是一種在語言模型(LLM)和多模態模型(MLLM)中用于優化注意力分配的關鍵機制&#xff0c;通過吸收模型中冗余的注意力權重&#xff0c;確保注意力資源不被無效或無關信息占用。以下是對這一概念的系統性解…

Spring Event 觀察者模型及事件和消息隊列之間的區別筆記

Spring Event觀察者模型&#xff1a;基于內置事件實現自定義監聽 在Spring框架中&#xff0c;觀察者模式通過事件驅動模型實現&#xff0c;允許組件間通過事件發布與監聽進行解耦通信。這一機制的核心在于ApplicationEvent、ApplicationListener和ApplicationEventPublisher等接…

【復活吧,我的愛機!】Ideapad300-15isk拆機升級:加內存條 + 換固態硬盤 + 換電源

寫在前面&#xff1a;本博客僅作記錄學習之用&#xff0c;部分圖片來自網絡&#xff0c;如需引用請注明出處&#xff0c;同時如有侵犯您的權益&#xff0c;請聯系刪除&#xff01; 文章目錄 前言升級成本升級流程電池健康度加內存條和換內存條光驅位加裝機械硬盤更換電池重裝系…

基于PyQt5的自動化任務管理軟件:高效、智能的任務調度與執行管理

基于PyQt5的自動化任務管理軟件&#xff1a;高效、智能的任務調度與執行管理 相關資源文件已經打包成EXE文件&#xff0c;可雙擊直接運行程序&#xff0c;且文章末尾已附上相關源碼&#xff0c;以供大家學習交流&#xff0c;博主主頁還有更多Python相關程序案例&#xff0c;秉著…

JavaScript 庫:全面解析與推薦

JavaScript 庫:全面解析與推薦 引言 JavaScript 作為當今最流行的前端開發語言之一,擁有豐富的庫和框架。這些庫和框架極大地簡化了開發工作,提高了開發效率。本文將全面解析 JavaScript 庫,并推薦一些優秀的庫,幫助開發者更好地掌握 JavaScript。 JavaScript 庫概述 …

C#從入門到精通(5)

目錄 第十二章 其他基礎知識 &#xff08;1&#xff09;抽象類和方法 &#xff08;2&#xff09;接口 &#xff08;3&#xff09;集合與索引器 &#xff08;4&#xff09;委托和匿名方法 &#xff08;5&#xff09;事件 &#xff08;6&#xff09;迭代器 &#xff08;7…

【區塊鏈安全 | 第十四篇】類型之值類型(一)

文章目錄 值類型布爾值整數運算符取模運算指數運算 定點數地址&#xff08;Address&#xff09;類型轉換地址成員balance 和 transfersendcall&#xff0c;delegatecall 和 staticcallcode 和 codehash 合約類型&#xff08;Contract Types&#xff09;固定大小字節數組&#x…