C++类的积极分子函数是不能作为回调函数的,C++类的成员函数是不可能看做回调函数的

回调函数是基于C编制程序的Windows
SDK的技术,不是对准C++的,程序员能够将三个C函数直接作为回调函数,但是若是准备直接接纳C++的积极分子函数作为回调函数将时有发生错误,甚至编写翻译就不能够因而。 

注:与tr一::function对象结合使用,能赢得更加好的效益,详情见http://blog.csdn.net/this_capslock/article/details/38564719

平时的C++成员函数都饱含了三个传递函数作为参数,亦即“this”指针,C++通
过传递2个针对性自己的指针给其成员函数从而完结程序函数能够访问C++的数目成员。那也得以知道为啥C++类的多少个实例能够共享成员函数不过确有不一样的
数据成员。由于this指针的效果,使得将1个CALLBACK型的成员函数作为回调函数安装时就会因为含有的this指针使得函数参数个数不兼容,从而
导致回调函数安装失败。

 

那样从理论上讲,C++类的分子函数是无法同日而语回调函数的。但咱们在用C++编制程序时总希望在类内完毕其效力,即要保持封装性,假如把回调函数写作普通函数有狼狈。经过网上寻找和友好研讨,发现了三种高超的章程,可以使得类成员函数当作回调函数使用。

回调函数是基于C编制程序的Windows
SDK的技巧,不是针对性C++的,程序员能够将1个C函数直接作为回调函数,但是只要打算直接选择C++的积极分子函数作为回调函数将发生错误,甚至编写翻译就不能够经过。 

此处运用Linux
C++中线程创造函数pthread_create举例,其原型如下:

平日的C++成员函数都饱含了二个传递函数作为参数,亦即“this”指针,C++通过传递3个针对性自个儿的指针给其成员函数从而完成程序函数可以访问C++的数目成员。那也得以知道为何C++类的四个实例能够共享成员函数不过确有差别的数额成员。由于this指针的功用,使得将1个CALLBACK型的成员函数作为回调函数安装时就会因为含有的this指针使得函数参数个数不相称,从而造成回调函数安装战败。

 

那样从理论上讲,C++类的分子函数是不能够作为回调函数的。但大家在用C++编制程序时总希望在类内完毕其效果,即要保持封装性,即使把回调函数写作普通函数有困难。经过网上搜寻和协调研商,发现了二种高超的主意,可以使得类成员函数当作回调函数使用。

[cpp] view
plain
copyprint?图片 1图片 2

此地运用Linux C++中线程创造函数pthread_create举例,其原型如下:

  1. int pthread_create( pthread_t *restrict tidp , const pthread_attr_t *restrict attr , void* (*start_rtn)(void*) , void *restrict arg );  

 

第多个参数为指向线程标识符的指针。

[cpp] view
plain
 copy

首个参数用来设置线程属性。

 

其八个参数是线程运转函数的苗头地址,即回调函数。

 print?图片 3图片 4

末尾1个参数是运转函数的参数。

  1. int pthread_create( pthread_t *restrict tidp , const pthread_attr_t *restrict attr , void* (*start_rtn)(void*) , void *restrict arg );  

此地我们只关切第拾个参数start_run,它是一个函数指针,指向三个以void*为参数,再次来到值为void*的函数,这么些函数被看作线程的回调函数使用,线程运维后便会履行该函数的代码。

 

格局一:回调函数为普通函数,但在函数体内进行成员函数

先是个参数为指向线程标识符的指针。

见之下代码:

其次个参数用来设置线程属性。

[cpp] view
plain
copyprint?图片 5图片 6

其四个参数是线程运转函数的伊始地址,即回调函数。

  1. class MyClass  
  2. {  
  3.     pthread_t TID;  
  4. public:  
  5.     void func()  
  6.     {  
  7.         //子线程执行代码  
  8.     }  
  9.   
  10.     bool startThread()  
  11.     {//运营子线程  
  12.         int ret = pthread_create( &TID , NULL , callback , this );  
  13.         if( ret != 0 )  
  14.             return false;  
  15.         else  
  16.             return true;  
  17.     }  
  18. };  
  19.   
  20. static void* callback( void* arg )  
  21. {//回调函数  
  22.     ((MyClass*)arg)->func();调用成员函数  
  23.     return NULL;  
  24. }  
  25.   
  26. int main()  
  27. {  
  28.     MyClass a;  
  29.     a.startThread();  
  30. }  

末段四个参数是运营函数的参数。

类MyClass要求在祥和之中开辟3个子线程来实施成员函数func()中的代码,
子线程通过调用startThread()成员函数来运转。那里将回调函数callback写在了类外面,传递的参数是3个对准MyClass对象的指针
(在pthrad_create()中由第五个参数this钦点),回调函数经过强制转换把void*变为MyClass*,然后再调用
arg->func()执行子线程的代码。

 

诸如此类做的原理是把当下目的的指针当作参数先交付二个表面函数,再由外部函数调用类成员
函数,以外部函数作为回调函数,但实施的是成员函数的效益,那样约等于在中游作了壹层转换。缺点是回调函数在类外,影响了封装性,那里把
callback()限定为static,幸免在其余文件中调用此函数。

那里大家只关心第多个参数start_run,它是3个函数指针,指向一个以void*为参数,重返值为void*的函数,那些函数被看成线程的回调函数使用,线程运维后便会进行该函数的代码。

主意二:回调函数为类内静态成员函数,在当中间调用成员函数

 

在点子壹上稍作更改,把回调函数搬到类MyClass里,那样就保险了封装性。代码如下:

艺术一:回调函数为常见函数,但在函数体内实施成员函数

[cpp] view
plain
copyprint?图片 7图片 8

见之下代码:

  1. class MyClass  
  2. {  
  3.     static MyClass* CurMy;//存款和储蓄回调函数调用的对象  
  4.     static void* callback(void*);//回调函数  
  5.     pthread_t TID;  
  6.     void func()  
  7.     {  
  8.         //子线程执行代码  
  9.     }  
  10.       
  11.     void setCurMy()  
  12.     {//设置当前目的为回调函数调用的目的  
  13.         CurMy = this;  
  14.     }  
  15. public:  
  16.     bool startThread()  
  17.     {//运营子线程  
  18.         setCurMy();  
  19.         int ret = pthread_create( &TID , NULL , MyClass::callback , NULL );  
  20.         if( ret != 0 )  
  21.             return false;  
  22.         else  
  23.             return true;  
  24.     }  
  25. };  
  26. MyClass* MyClass::CurMy = NULL;  
  27. void* MyClass::callback(void*)  
  28. {  
  29.     CurMy->func();  
  30.     return NULL;  
  31. }  
  32.   
  33. int main()  
  34. {  
  35.     MyClass a;  
  36.     a.startThread();  
  37. }  

[cpp] view
plain
 copy


MyClass有了三个静态数据成员CurMy和二个静态成员函数callback。CurMy用来存款和储蓄叁个目的的指针,充当方法一中回调函数的参数
arg。callback当作回调函数,执行CurMy->func()的代码。每回建立线程前先要调用setCurMy()来让CurMy指向当
前协调。

 

以此点子的好处时封装性获得了很好的保卫安全,MyClass对外只公开贰个接口
startThread(),子线程代码和回调函数都被设为私有,外界不可知。别的未有占用callback的参数,能够从外边传递参数进来。但种种对象
运营子线程前必然要留心先调用setCurMy()让CurMy正确的对准本人,不然将为其余对象开启线程,那样很吸引非常惨重的后果。

 print?图片 9图片 10

主意三:对成员函数举行强制转换,当作回调函数

  1. class MyClass  
  2. {  
  3.     pthread_t TID;  
  4. public:  
  5.     void func()  
  6.     {  
  7.         //子线程执行代码  
  8.     }  
  9.   
  10.     bool startThread()  
  11.     {//运营子线程  
  12.         int ret = pthread_create( &TID , NULL , callback , this );  
  13.         if( ret != 0 )  
  14.             return false;  
  15.         else  
  16.             return true;  
  17.     }  
  18. };  
  19.   
  20. static void* callback( void* arg )  
  21. {//回调函数  
  22.     ((MyClass*)arg)->func();调用成员函数  
  23.     return NULL;  
  24. }  
  25.   
  26. int main()  
  27. {  
  28.     MyClass a;  
  29.     a.startThread();  
  30. }  

代码如下:

 

[cpp] view
plain
copyprint?图片 11图片 12

类MyClass必要在温馨之中开辟3个子线程来实施成员函数func()中的代码,子线程通过调用startThread()成员函数来运转。那里将回调函数callback写在了类外面,传递的参数是2个针对性MyClass对象的指针(在pthrad_create()中由第陆个参数this钦定),回调函数经过强制转换把void*变为MyClass*,然后再调用arg->func()执行子线程的代码。

  1. class MyClass  
  2. {  
  3.     pthread_t TID;  
  4.     void func()  
  5.     {  
  6.         //子线程执行代码  
  7.     }  
  8. public:  
  9.     bool startThread()  
  10.     {//运行子线程  
  11.         typedef void* (*FUNC)(void*);//定义FUNC类型是1个对准函数的指针,该函数参数为void*,重临值为void*  
  12.         FUNC callback = (FUNC)&MyClass::func;//强制转换func()的品种  
  13.         int ret = pthread_create( &TID , NULL , callback , this );  
  14.         if( ret != 0 )  
  15.             return false;  
  16.         else  
  17.             return true;  
  18.     }  
  19. };  
  20.   
  21. int main()  
  22. {  
  23.     MyClass a;  
  24.     a.startThread();  
  25. }  

如此做的原理是把最近目的的指针当作参数先交给2个外表函数,再由外部函数调用类成员函数,以外部函数作为回调函数,但实践的是成员函数的效益,这样也就是在中游作了一层转换。缺点是回调函数在类外,影响了封装性,那里把callback()限定为static,幸免在此外文件中调用此函数。

以此点子是原理是,MyClass::func最后会转接成
void func(MyClass *this);
也便是说在原第3个参数前插入指向对象自小编的this指针。能够应用那个本性写二个非静态类成员方法来直接当做线程回调函数。对编写翻译器而言,void
(MyClass::*FUNC1)()和void*
(*FUNC)(void*)那二种函数指针即便看起来很分歧,但她们的末梢方式是千篇一律的,由此就能够把成员函数指针强制转换到普通函数的指针来作为回
调函数。在确立线程时要把最近指标的指针this当作参数字传送给回调函数(成员函数func),那样才能通晓线程是针对哪个指标建立的。

 

方法3的封装性比办法②更加好,因为不关乎多少个目的共用3个静态成员的难题,各种对象能够独立地运营本身的线程而不影响别的对象。

方法二:回调函数为类内静态成员函数,在其内部调用成员函数

一时半刻就列出那几个办法,以后发现更加好的再来补充,over

在方式一上稍作更改,把回调函数搬到类MyClass里,那样就保障了封装性。代码如下:

 

[cpp] view
plain
 copy

 

 print?图片 13图片 14

  1. class MyClass  
  2. {  
  3.     static MyClass* CurMy;//存款和储蓄回调函数调用的对象  
  4.     static void* callback(void*);//回调函数  
  5.     pthread_t TID;  
  6.     void func()  
  7.     {  
  8.         //子线程执行代码  
  9.     }  
  10.       
  11.     void setCurMy()  
  12.     {//设置当前指标为回调函数调用的指标  
  13.         CurMy = this;  
  14.     }  
  15. public:  
  16.     bool startThread()  
  17.     {//运转子线程  
  18.         setCurMy();  
  19.         int ret = pthread_create( &TID , NULL , MyClass::callback , NULL );  
  20.         if( ret != 0 )  
  21.             return false;  
  22.         else  
  23.             return true;  
  24.     }  
  25. };  
  26. MyClass* MyClass::CurMy = NULL;  
  27. void* MyClass::callback(void*)  
  28. {  
  29.     CurMy->func();  
  30.     return NULL;  
  31. }  
  32.   
  33. int main()  
  34. {  
  35.     MyClass a;  
  36.     a.startThread();  
  37. }  

类MyClass有了一个静态数据成员CurMy和叁个静态成员函数callback。CurMy用来存款和储蓄七个对象的指针,充当方法一中回调函数的参数arg。callback当作回调函数,执行CurMy->func()的代码。每便建立线程前先要调用setCurMy()来让CurMy指向当前祥和。

 

本条主意的补益时封装性获得了很好的珍重,MyClass对外只公开多少个接口startThread(),子线程代码和回调函数都被设为私有,外界不可知。此外未有据为己有callback的参数,能够从外面传递参数进来。但各样对象运营子线程前必然要小心先调用setCurMy()让CurMy正确的对准自己,不然将为此外对象开启线程,那样很吸引十分的惨重的后果。

 

艺术三:对成员函数实行强制转换,当作回调函数

代码如下:

 

[cpp] view
plain
 copy

 

 print?图片 15图片 16

  1. class MyClass  
  2. {  
  3.     pthread_t TID;  
  4.     void func()  
  5.     {  
  6.         //子线程执行代码  
  7.     }  
  8. public:  
  9.     bool startThread()  
  10.     {//运行子线程  
  11.         typedef void* (*FUNC)(void*);//定义FUNC类型是3个对准函数的指针,该函数参数为void*,再次来到值为void*  
  12.         FUNC callback = (FUNC)&MyClass::func;//强制转换func()的门类  
  13.         int ret = pthread_create( &TID , NULL , callback , this );  
  14.         if( ret != 0 )  
  15.             return false;  
  16.         else  
  17.             return true;  
  18.     }  
  19. };  
  20.   
  21. int main()  
  22. {  
  23.     MyClass a;  
  24.     a.startThread();  
  25. }  

本条方式是规律是,MyClass::func最终会转化成 void func(MyClass *this);
相当于说在原第三个参数前插入指向对象自作者的this指针。能够行使这一个特点写1个非静态类成员方法来直接作为线程回调函数。对编写翻译器而言,void
(MyClass::*FUNC1)()和void*
(*FUNC)(void*)这二种函数指针纵然看上去很分裂等,但她们的终极情势是同等的,由此就能够把成员函数指针强制转换来普通函数的指针来作为回调函数。在确立线程时要把当下指标的指针this当作参数字传送给回调函数(成员函数func),这样才能分晓线程是针对性哪个指标建立的。

 

主意三的封装性比办法2更加好,因为不关乎三个对象共用一个静态成员的标题,各个对象足以独立地运营自个儿的线程而不影响别的对象。

 

权且就列出那些艺术,现在发现更加好的再来补充,over

http://blog.csdn.net/this\_capslock/article/details/17001003


4楼 eziowayne 2015-04-17 15:38发表 [回复]
图片 17

民用推举第一种办法,第二种办法适用面窄,第二种是谬误的章程,千万不可能那样用。

3楼 __JacHan 2014-04-28 14:44发表 [回复]
图片 18

用的时候用楼主的法子三其实调不通,论坛里面有人如此表达的:为了兑现回调,我们务必把this指针给转换掉!可为了在该函数中能够一直操作该类中的成员,大家亟须保留this指针!所以那是争辩的,通过更换指针的手段是不能够完成指标的!
来自:http://bbs.csdn.net/topics/360051927
还是用tr1::function/bind实现了

 

相关文章