C/C++回调函数实现与std::function和std::bind介绍

1 概述

  • 回调函数是一种编程模式,指的是将一个函数作为参数传递给另一个函数,并在某个特定事件发生时或满足某些条件时由该函数调用。
  • 这种机制允许你定义在特定事件发生时应执行的代码,从而实现更灵活和模块化的程序设计。

2 传统C/C++回调实现方式

  • 传统C/C++实现回调,主要通过函数指针来实现。

  • 有这样一个场景,某业务系统需要检测环境温度,当温度大于50度时进行告警,告警接口就可以作为回调函数,在温度大于50度时调用。这里通过随机生成一个温度值,模式现实场景。

  • 示例
    *

    c 复制代码
      #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表示式。

  • 基本语法
    *

    c 复制代码
      #include <functional>
    
      std::function<返回值类型(参数类型列表)> 函数对象;
  • 示例
    *

    c 复制代码
      #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是一个函数模板,用于将函数或成员函数与其参数绑定,生成一个新的可调用对象。

  • 基本语法
    *

    c 复制代码
      // 绑定非类成员函数/变量
      auto f = std::bind(可调用对象地址, 绑定的参数/占位符);
      // 绑定类成员函/变量
      auto f = std::bind(类函数/成员地址, 类实例对象地址, 绑定的参数/占位符);
  • 示例
    *

    c 复制代码
      #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; // 输出 15
    
    
          MyClass obj;
    
          // 绑定类成员函数
          auto boundMultiply = std::bind(&MyClass::multiply, &obj, std::placeholders::_1, std::placeholders::_2);
    
          std::cout << "Result: " << boundMultiply(3, 4) << std::endl; // 输出 12
    
          system("pause");
          return 0;
      }

3.3 C++11实现回调

  • 介绍完std::functionstd::bind再看下如何使用C++11语法实现回调。

  • 回调函数为普通函数时示例

    c 复制代码
      #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时示例

    c 复制代码
      #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 已超阈值,告警 ...
        结束业务
        请按任意键继续. . .
c 复制代码
  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;
  }
相关推荐
Dovis(誓平步青云)1 小时前
探索C++标准模板库(STL):String接口的底层实现(下篇)
开发语言·c++·stl·string
草莓熊Lotso1 小时前
【数据结构初阶】--算法复杂度的深度解析
c语言·开发语言·数据结构·经验分享·笔记·其他·算法
KyollBM1 小时前
【CF】Day75——CF (Div. 2) B (数学 + 贪心) + CF 882 (Div. 2) C (01Trie | 区间最大异或和)
c语言·c++·算法
feiyangqingyun2 小时前
Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
c++·qt·udp·gb28181
CV点灯大师2 小时前
C++算法训练营 Day10 栈与队列(1)
c++·redis·算法
CodeOfCC2 小时前
c语言 封装跨平台线程头文件
linux·c语言·windows
成工小白3 小时前
【C++ 】智能指针:内存管理的 “自动导航仪”
开发语言·c++·智能指针
sc写算法3 小时前
基于nlohmann/json 实现 从C++对象转换成JSON数据格式
开发语言·c++·json
SunkingYang3 小时前
C++中如何遍历map?
c++·stl·map·遍历·方法
Andrew_Xzw3 小时前
数据结构与算法(快速基础C++版)
开发语言·数据结构·c++·python·深度学习·算法