C++ 静态回调函数

在注册回调函数时,要求回调函数必须是静态函数或全局函数。

  • 如果使用全局函数,会毁坏类的封装性;
  • 如果在类中不使用static属性的回调函数,则会出现“invalid use of non-static function”的编译错误。
  • 如果在类Class A中使用static属性,将使得该回调函数只能访问类中的静态成员,而无法访问非静态成员,这常常不能满足实际应用的要求。

于是,进入尴尬境地。

 

为了保持callback function依然为static,同时又能访问类中的所有成员,有两种方法。

第一种方法

将一个指向类实例的指针作为callback function的参数传递进去,通过该指针调用类的非静态成员。

  • 有些回调函数有固定的定义,无法接受额外的参数,如 A* p_this。
  • 但也有些回调函数有考虑这个问题,提供user_data作为参数传递到回调函数当中。以下二例说明。

例1,在libusb中,函数libusb_fill_bulk_transfer调用时需要注册一个回调函数 xfer_callback,而在xfer_callback中需要访问类中的非静态成员,怎么办呢?

先看libusb_fill_bulk_transfer的定义:

static void libusb_fill_bulk_transfer	(	
struct libusb_transfer * 	transfer,
libusb_device_handle * 	dev_handle,
unsigned char 	endpoint,
unsigned char * 	buffer,
int 	length,
libusb_transfer_cb_fn 	callback,
void * 	user_data,
unsigned int 	timeout 
)		

Parameters:
transfer	the transfer to populate
dev_handle	handle of the device that will handle the transfer
endpoint	address of the endpoint where this transfer will be sent
buffer	        data buffer
length	        length of data buffer
callback	callback function to be invoked on transfer completion
user_data	user data to pass to callback function
timeout	        timeout for the transfer in milliseconds

在libusb_fill_bulk_transfer中,提供了一个user_data的函数参数(第7个参数)用于传递在xfer_callback中所需要的数据(如类中的非静态成员)。

libusb_fill_bulk_transfer (transfers, dev_handle, endpoint_stream,
                           databuffers[i], reqsize * pktsize, xfer_callback, this, 500);

在这里,我们将类的指针this作为user_data传递进去。libusb_fill_bulk_transfer做的事情是把this传递到transfers中(在transfer的结构定义中包含user_data),而transfers又是 xfer_callback 唯一的参数(xfer_callback的定义是固定的,为libusb_transfer_cb_fn),从而实现将this传递进xfer_callback的目的。进而,在xfer_callback就能够通过this指针访问类中的所有成员。

 

例2,类似地,在C++多线程编程中,在构造新的线程时,需要注册一个回调函数。如果回调函数是定义在类当中,同时又需要访问类中的其它非静态成员,那么就不能使用

std::thread thread_ros(thread_ros_proc_func);

来初始化,而可以使用

std::thread thread_ros(&classname::thread_ros_proc_func, this);

来初始化。

 

第二种方法

我们会自然想到在类中再定义一个static pointer指向这个类的对象,这样在static callback function中就可以通过调用static pointer来合理访问类对象当中的成员,包括static member和non-static member。如下:

class A()
{
    static void a(); //静态回调函数
    void b();  //非静态函数 
    static A * pThis;   //静态对象指针
}

A * A::pThis=NULL;
A::A()   //构造函数中将this指针赋给pThis,使得回调函数能通过pThis指针访问本对象
{
    pThis=this;
}
void A::a()
{
    if (pThis==NULL) return;
    pThis->b(); //回调函数中调用非静态函数 
}

 

但再仔细一想,由于该指针的static属性,使得它只能指向一个类的对象。当有多个类的实例对象时,就会出现问题。

下面给出一种方法解决多个类实例对象时static pointer只能指向一个对象的尴尬。

用映射表存所有对象地址,每个对象保存自己的ID号。

  typedef CMap<UINT,UINT,A*,A*> CAMap;
  class A()
  {
      static void a(); //静态回调函数
      void b();  //非静态函数 
      int m_ID;  //本对象在列表中的ID号
      static int m_SID;   //静态当前对象ID        (需要时,将m_ID赋值给m_SID以起到调用本对象函数的功能)
      static CAMap m_Map; //静态对象映射表
  }  
  
  CAMap A::m_Map;
  int   A::m_SID=0;
  
 
  A::A()   //构造函数中将this指针赋给pThis,使得回调函数能通过pThis指针访问本对象
  {
      if(m_Map.IsEmpty())
      {
         m_ID=1;
      }
      else
      { 
        m_ID=m_Map.GetCount()+1;
      }
      m_Map.SetAt( m_ID, this );
  }
  void A::a()
  {
      if (m_Map.IsEmpty()) return;
      A * pThis=NULL;
      if(m_Map.Lookup(m_SID,pThis))
      {
         pThis->b(); //回调函数中调用非静态函数 
      };
  }

 

 

Reference:

How to pass callback function to libusb bulk transfer function in C++ Class

how to pass a non static-member function as a callback?

C++将类的成员函数作为回调函数 - qing666888的专栏 - CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值