C++实现回调函数的几种方式

这篇具有很好参考价值的文章主要介绍了C++实现回调函数的几种方式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


通常认为通过函数指针在其他地方调用函数的过程称为回调,被调用的函数称为回调函数,函数指针通过传参方式传递。
在C++的实际应用中,有很多实现回调函数的方式,不一定要传递函数指针才能实现回调,只要实现了回调的功能,都叫回调函数。
回调函数是和调用者在同一线程,使用中要注意线程安全。
本章通过几个例子介绍C++实现回调函数的几种方式。

C++虚函数特性实现回调函数

这是最具C++特征的回调函数,基类定义纯虚函数,派生类实现虚函数,基类指针可以指向派生类,使用基类指针就可以调用派生类的虚函数,从而实现回调。
不足:利用虚函数特性实现回调函数的方式需要定义基类,通常是子类对父类的回调,当子类层级太多时需要逐级回调,实现起来比较繁琐。
代码实现:

#ifndef MANAGERINH_H
#define MANAGERINH_H

#include<string>
using namespace std;
class messageBase {//消息回调基类
public:
    messageBase() {};
    virtual ~messageBase() {};
    virtual void msgCallback(std::string msg)=0;
};

class employeeINH{//员工类
public:
    employeeINH(messageBase *msgBase){
        m_messageBase = msgBase;
    }
    void dowork(int count) {
        int sum = 0;
        for(int index=0;index<count;index++)
            sum += index*10;
        std::string msg = "total:" + to_string(sum);
        if(m_messageBase)
            m_messageBase->msgCallback(msg);//回调函数
    }
private:
    messageBase *m_messageBase;//消息回调基类对象指针,可以指向它的派生类,也就是 ManagerINH
};

class ManagerINH : public messageBase{//经理类,继承于消息回调基类
public:
    ManagerINH(){
        //创建子对象时,把父对象的指针传递过去
        pemployeeINH = new employeeINH(this);
    }

    virtual void msgCallback(std::string msg){//实现虚函数
        printf("result=%s\n",msg.c_str());
    }

    void sendwork(int num){
        pemployeeINH->dowork(num);
    }
private:
    employeeINH *pemployeeINH;
};
#endif // MANAGERINH_H

调用测试

ManagerINH mManagerINH;
mManagerINH.sendwork(10);

打印

result=total:450

C++结构体指针实现回调函数

把全局回调函数的指针、定义结构体对象的指针封装在一个结构体里,把这个结构体指针传递给子类,子类的子类等等,可以在程序的任何地方实现回调。
代码实现,managercon.h

#ifndef MANAGERCON_H
#define MANAGERCON_H

#include <string>
//回调结构体
struct ChwContext {
    //data      回调数据指针
    //nb_data   回调数据长度
    //user_this 指向当前结构体的指针
    void (*receiveQt)(char *data, int nb_data,void* user_this);
    void *user_callback;//回调函数所在对象的指针
};
#define safe_delete(a) {if( (a)) {delete (a); (a) = NULL;}}
#define safe_deleteA(a) {if( (a)) {delete[] (a); (a) = NULL;}}
#define safe_free(a) {if( (a)) {free((a)); (a) = NULL;}}

class EmployeeCON//员工类
{
public:
    EmployeeCON(ChwContext *pcontext){
        pChwContext = pcontext;
    }
    ChwContext *pChwContext;//由父对象传递过来的回调结构体指针

    void dowork(int count){
        int sum = 0;
        for(int index=0;index<count;index++)
            sum += index*10;

        std::string tmpstr = "total:" + std::to_string(sum);
        pChwContext->receiveQt((char*)tmpstr.c_str(),tmpstr.size(),pChwContext);//执行回调
    }
};

class ManagerCON//经理类
{
public:
    ManagerCON();
    ~ManagerCON();

    void sendwork(int count);
    void callback_receive(std::string msg);//回调函数
private:
    ChwContext *p_ChwContext;//回调结构体,在回调函数所在对象声明和定义,可传递给子类,子类的子类等
    EmployeeCON *pEmployeeCON;
};

#endif // MANAGERCON_H

managercon.cpp

#include "managercon.h"
//全局回调函数
void g_callback_receive(char *data, int nb_data ,void *obj) {
    if (obj == nullptr)
        return;
    ChwContext  *contx = (ChwContext*) obj;
    ManagerCON *mc = (ManagerCON*) contx->user_callback;
    std::string tmpstr(data,nb_data);
    mc->callback_receive(tmpstr);
}

ManagerCON::ManagerCON()
{
    p_ChwContext = new ChwContext;
    p_ChwContext->receiveQt = g_callback_receive;
    p_ChwContext->user_callback = this;

    pEmployeeCON = new EmployeeCON(p_ChwContext);
}

ManagerCON::~ManagerCON()
{
    safe_delete(pEmployeeCON);
    safe_delete(p_ChwContext);
}

void ManagerCON::sendwork(int count)
{
    pEmployeeCON->dowork(count);
}

void ManagerCON::callback_receive(std::string msg)
{
    printf("msg=%s\n",msg.c_str());
}

调用测试

ManagerCON mManagerCON;
mManagerCON.sendwork(10);

打印

msg=total:450

C++11新特性td::tr1::function和std::tr1::bind实现回调函数

关于新特性参考:C++ std::tr1::function和std::tr1::bind模板类介绍,qt测试,这里不多说,直接上代码。
managerbind.h

#ifndef MANAGERBIND_H
#define MANAGERBIND_H

#include <iostream>
#include <tr1/functional>
#include <string>
class employeeBind{//员工类
public:
    employeeBind(){
    }
    void dowork(int count){
        int sum = 0;
        for(int index=0;index<count;index++)
            sum += index*10;
        std::string msg = "total:" + std::to_string(sum);
        if(Callback)
            Callback(msg);//回调函数
    }
    std::tr1::function<void(std::string)> Callback;
};

class ManagerBind//经理类
{
public:
    ManagerBind();

    employeeBind memployeeBind;
    void sendwork(int num);
    void callbackBD(std::string msg);
};

#endif // MANAGERBIND_H

managerbind.cpp

#include "managerbind.h"

ManagerBind::ManagerBind()
{
    memployeeBind.Callback = std::tr1::bind(&ManagerBind::callbackBD,this, std::tr1::placeholders::_1);
}

void ManagerBind::sendwork(int num){
    memployeeBind.dowork(num);
}

void ManagerBind::callbackBD(std::string msg)
{
    printf("msg=%s\n",msg.c_str());
}

调用测试

ManagerBind mManagerBind;
mManagerBind.sendwork(10);

打印

msg=total:450

C++联合体union实现回调函数

union也叫联合体,在一个“联合体”内可以定义多种不同数据类型的变量,这些变量共享同一段内存,存储在内存中的起始地址相同,使用了覆盖计数,以达到节省空间的目的。union变量所占用的内存长度等于最长的成员变量的内存长度。
union的其中一个作用是实现简洁的线程回调函数。
managerunion.h

#ifndef MANAGERUNION_H
#define MANAGERUNION_H
#include <pthread.h>
#include <iostream>
#include <string>

class ManagerUnion;
//定义函数指针数据类型
typedef void* (ManagerUnion::*ThreadMeth)(void *);
typedef void* (*pThreadMethod)(void *);
class ManagerUnion
{
public:
    ManagerUnion();
    void startThread();
    void callbackUM(void *);
    int count;
    pthread_t m_threadID;
};
#endif // MANAGERUNION_H

managerunion.cpp

#include "managerunion.h"
ManagerUnion::ManagerUnion()
{
    count = 502;
    printf("ManagerUnion::ManagerUnion tid = %lu\n", pthread_self());
}

void ManagerUnion::startThread()
{
    union{//两个函数指针共享同一段内存
        pThreadMethod pFunc;
        void* (ManagerUnion::*ThreadMeth)(void *);
    }obj;

    obj.ThreadMeth = (ThreadMeth)&ManagerUnion::callbackUM;
    pthread_create(&m_threadID,0,obj.pFunc,this);//创建线程
}

//回调函数,也是线程处理函数,在子线程运行,调用的还是主类的函数
void ManagerUnion::callbackUM(void *)
{
    printf("ManagerUnion::callbackUM tid = %lu\n", pthread_self());

    printf("count=%d\n",count);
}

调用测试

ManagerUnion mManagerUnion;
mManagerUnion.startThread();

打印文章来源地址https://www.toymoban.com/news/detail-602518.html

ManagerUnion::ManagerUnion tid = 139898503038848
ManagerUnion::callbackUM tid = 139898191017728
count=502

到了这里,关于C++实现回调函数的几种方式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【基础算法】矩阵的几种基本运算 & C++实现

            从线性代数中我们已知,两个矩阵可以进行加减乘运算,但矩阵之间没有除法运算。(下面以3×3矩阵为例):          矩阵的数乘运算类属与两矩阵相乘的一种特殊形式(数乘矩阵的这个数,我们可以将其化为对角线为该数,其余位置都为0的矩阵,再用该对

    2024年02月11日
    浏览(38)
  • Baumer工业相机堡盟工业相机使用BGAPI SDK将图像数据转换为Bitmap的几种方式(C++)(Mono)

    Baumer工业相机堡盟相机是一种高性能、高质量的工业相机,可用于各种应用场景,如物体检测、计数和识别、运动分析和图像处理。 Baumer的万兆网相机拥有出色的图像处理性能,可以实时传输高分辨率图像。此外,该相机还具有快速数据传输、低功耗、易于集成以及高度可扩

    2024年02月03日
    浏览(53)
  • C 语言函数宏的几种封装方式

    目录 1. 函数宏介绍 2. {} 方式 3. do{...}while(0) 方式 4. ({}) 方式 5. 总结 函数宏,即包含多条语句的宏定义,其通常为某一被频繁调用的功能的语句封装,且不想通过函数方式封装来降低额外的弹栈压栈开销。 函数宏本质上为宏,可以直接进行定义,例如: 但上述的宏具有一个

    2024年02月09日
    浏览(35)
  • C++回调函数 匿名函数,类中的方法做为回调函数

    C++中的回调函数和匿名函数都是函数指针或函数对象的使用形式。下面分别介绍它们的使用方法。 回调函数是一种函数指针,它允许将函数作为参数传递给另一个函数,并在需要时调用它。这种技术通常用于事件处理、异步处理和状态机等应用中。 下面是一个简单的示例,

    2024年02月01日
    浏览(38)
  • C++中的回调函数

    C++中的回调函数是指将一个 函数作为参数 传递 给另一个函数 ,并在另一个函数中 调用 该函数。 这种技术被称为函数指针或函数对象。 回调函数通常用于 异步编程 中,例如事件处理程序、GUI编程、网络编程等。 在这些情况下,程序需要在某个事件发生时执行某些操作,

    2024年02月06日
    浏览(38)
  • C++笔记之回调函数的演变

    code review! 代码

    2024年02月13日
    浏览(24)
  • Java开发或调用WebService的几种方式

    1.服务端开发与发布 编写接口 编写接口的实现类 发布服务 访问已发布的WebService服务 打开浏览器输入http://127.0.0.1:8888/JaxWSTest?wsdl访问,如下面内容 截图内容1 浏览器中输入wsdl文档中的 http://127.0.0.1:8888/JaxWSTest?xsd=1可查看绑定的参数等信息看如下图: 截图内容2 jdk自带生成W

    2024年01月17日
    浏览(41)
  • c++初始化vector的几种方法

    在C++中,vector是一种动态数组,可以在运行时自由添加、删除元素。初始化vector是创建一个vector对象并为其分配内存空间的过程。以下是C++中初始化vector的几种方法: 默认构造函数 使用默认构造函数创建一个空的vector,如下所示: std::vectorint vec; // 创建空vector 这种方式可用

    2024年02月16日
    浏览(33)
  • C++技能 ( 2 ) - const的几种使用【详解】

    C++高性能优化编程系列 深入理解软件架构设计系列 高级C++并发线程编程 C++技能系列 期待你的关注哦!!! 生活就是上帝发给你的一张手牌,无论多烂,你都得拿着。 Life is god give you a hand, no matter how bad, you have to take. (1)表示常量a,不能改变a的值 (1)表示常量引用,a代

    2024年02月09日
    浏览(26)
  • C++中创建二维数组的几种方法

    或者

    2024年02月15日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包