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

发布于:2025-03-30 ⋅ 阅读:(70) ⋅ 点赞:(0)

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; // 输出 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语法实现回调。

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

    •   #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;
      }
    

网站公告

今日签到

点亮在社区的每一天
去签到