c++回调函数的两种实现方式和原理

这里讲解两种方式的实现和原理,比较推荐方式2:

  1. 函数指针:使用了裸指针

  2. 类对象智能指针

一、函数指针

1、模块B要调用模块A的函数fun(),大致原理如下

  • 在模块A中定义static fun()

  • 模块B中定义一个registercallback的接口

  • 模块A通过调用registercallback接口,把指向fun()的函数指针设置到模块B中,模块B将函数指针保存起来

  • 模块B 要调用时,通过保存的函数指针调用

2、具体实现

class A 中保存class B 的对象指针。

class B想要调用classA的onCallback函数。

class A {
public:
        //calssB 要调用的函数onCallback,必须是静态
        //这里为什么要是静态函数:
        //因为静态成员函数可以用普通函数指针来存储,普通成员函数智能用类成员函数指针来存储。在注册回调传入改函数的函数指针时只能用普通函数指针
       static bool onCallback(int a, void *context) { 
              cout << "onCallback"  << a << endl;
              A* a = (A*)context; //可以通过a来调用类的非静态成员
              return true;
       }

       //classA 注册回调函数,将onCallback的函数指针传给classB
       void setCb() {
              if (m_pB) {
                     m_pB->registerCallBack(onCallback, this);

                     //传入this指针的原因:
                     // onCallback是一个静态成员函数,不能调用类的普通成员函数和普通成员变量
                     //传入this指针后,就能通过this指针来调用类的普通成员函数和普通成员变量
                     //使用方法 A* a = (A*)contex;
              }
       }
            //保存class B的对象指针
       std::shared_ptr<B> m_pB = nullptr;
};
//定义回调函数的原型,要和calssA的被回调函数一致
typedef bool (*onCallback)(int a, void *context);
class B {
public:
       onCallback m_cb;
       void* m_context;

       void registerCallBack(onCallback cb, void* context) {
              m_cb = cb;
              m_context = context;
       }
       void test(int a) {
              if (m_cb)
                     m_cb(a, m_context); //通过保存的函数指针回调classA的函数
       }
};
int main()
{
       std::shared_ptr<A> a(new A());
       std::shared_ptr<B> ptr(new B());
       a->m_pB = ptr;
       a->setCb();

       ptr->test(1);
       return 0;
}

二、类对象智能指针

1、模块B要调用模块A的函数fun(),大致原理如下

  • 在模块A中保存模块B的对象指针

  • 将模块A的this对象传递到模块B,并且在模块B中用weak_ptr保存起来

  • B调用A的函数时,通过保存的B的对象指针来调用。

2、具体实现

//定义类,并且在类中定义classB要调用的A的函数
//class A继承于该类,并实现该类定义的虚函数
class EventCallback {
public:
       virtual void onCallback(int a) {};
};

typedef std::weak_ptr<EventCallback> EVENTCALLBACK_WEAK;


class B {
public:
       //定义锁,在调用回调函数之前都要锁住,该锁在作用域结束后unlock
       std::recursive_mutex m_lockCb;

       //保存对象A的指针,必须用weak_ptr
       //如果用shared_ptr,就会出现A中保存B的智能指针,B中也保存A的智能指针
       //出现智能指针的交叉引用,会导致释放时都释放不掉,出现内存泄漏
       EVENTCALLBACK_WEAK m_cb;

       //将A对象指针保存下来
       void registerCallBack(EVENTCALLBACK_WEAK cb) {
              m_cb = cb;
       }
       void test(int a) {
              std::lock_guard<std::recursive_mutex> autoLock(m_lockCb); //上锁
              auto cb = m_cb.lock(); //lock转为shared_ptr
              if (cb)
                     cb->onCallback(a); //回调A的函数
       }
};
//继承EventCallback
//通过enable_shared_from_this来使用this智能指针
class A:public EventCallback,public std::enable_shared_from_this<A>{
public:
       //class B 要调用的函数,实现的EventCallback中的虚函数
       void onCallback(int a) {
              cout << "onCallback"  << a << endl;
       }

       void setCb() {
              if (m_pB) {
                     //通过shared_frome_this来获取对象本身的指针,不能直接用this
                     std::weak_ptr<A> self = shared_from_this();
                     m_pB->registerCallBack(self);  //注册回调函数
                    //这里也可以看出为什么要继承于EventCallback:
                    //因为 m_pB->registerCallBack的参数类型是EVENTCALLBACK_WEAK
                    //A继承了EventCallback,就能把A对象作为实参传进去
              }
       }

       std::shared_ptr<B> m_pB = nullptr;
};
int main()
{
       std::shared_ptr<A> a(new A());
       std::shared_ptr<B> b(new B());
       a->m_pB = b;
       a->setCb();
       b->test(6);
       return 0;
}

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值