把C++类成员方法直接作为线程回调函数

1)运算符 ->* 和.*

这两个运算符 平时很不常用。而且在项目中看到也容易忽视。他们是可以绑定this指针的运算符,看下面的例子:


class CA
{
public:
    int m_i0;
    void m_f0( int value)
    {
        m_i0 = value;
        std::cout << "<<m_f0>> argv=" << value << std::endl;
    }
private:
    int m_i1;
    void m_f1(int value)
    {
        m_i1 = value;
        std::cout << "<<m_f1>> argv=" << value << std::endl;
    }
};


typedef void (CA::*F0)(int);

int main(int c, char *v[])
{
    CA a;
    a.m_i0 = 9;
    int CA::*pm = &CA::m_i0;
    a.*pm = 100;
    
    /*
    int CA::*pr = &CA::m_i1;
    a.*pr = 100;
    错误	1	error C2248 : “CA::m_i1” : 无法访问 private 成员(在“CA”类中声明)
    */

    F0 func = &CA::m_f0;
    (a.*func) (100);

    /*F0 func = &CA::m_f1;*/

    return 0;
}
可以自己运行下 体会下。这个方法是可以 绑定成员函数指针作为回调的,前提是你需要有完整的实例类。


2)奇技淫巧

我以前写线程时要么老老实实照着声明写,要么使用C++类的静态成员函数来作为回调函数,经常会因为线程代码而破坏封装.之前虽然知道类成员函数的展开形式,但从没想过利用过它,昨天看深入ATL时无意中学会了这一招:)

  类成员方法是一个比较特殊的函数,它在编译时会被转化成普通函数,比如有TMyClass类:

class TMyClass
{
    void Func();
};


这个TMyClass::Func最终会转化成 void Func(TMyClass *this); 也就是说在原第一个参数前插入指向对象本身的this指针。

  我们可以利用这个特性写一个非静态类成员方法来直接作为线程回调函数,先看_beginthread函数的定义:

  unsigned long _RTLENTRY _EXPFUNC _beginthread (void (_USERENTRY *__start)(void *),unsigned __stksize, void *__arg);

  其中的第一个参数就是作为线程执行主体的回调函数。它的原型是:void Func(void *),这个void*参数是作为自定义数据传入的。对比一下上面所说的TMyClass::Func的最终形式,它正好可以符合这里的要求。

  现在做个实验:

#include <stdio.h>
#include <process.h>

class TMyClass

{
    int m_nCount;
    int m_nId;
public:
    TMyClass(int nId,int nCount)
        :m_nId(nId),m_nCount(nCount)
    { }

    void _USERENTRY ThreadProc()            // 类成员方法
    {
        for(int i=0; i<m_nCount; i++)       // 根据m_nCount成员打印一排数字
        {
            printf("Class%d : %d\n",m_nId,i);
        }
    }
};

int main(int argc, char* argv[])
{

// 联合类,用于转换类成员方法指针到普通函数指针(试过编译器不允许在这两种函数之间强制转换),不知道有没有更好的方法。

    union { 
        void (_USERENTRY *ThreadProc)(void *);
        void (_USERENTRY TMyClass::*MemberProc)();
    } Proc;     // 尽管联合里的两种函数类型现在看起来有很大不同,但它们的最终形式是相同的。

 


    TMyClass MyClass1(1,10),MyClass2(2,5); // 产生两个TMyClass对象

    Proc.MemberProc = &TMyClass::ThreadProc;   // 转换,Proc.ThreadProc就是对应的普通函数指针了

    _beginthread(Proc.ThreadProc,4096,&MyClass1);   // 开始线程,这里的Proc.ThreadProc实际上是TMyClass::ThreadProc, 它要的this指针是我们给的&MyClass1。
    _beginthread(Proc.ThreadProc,4096,&MyClass2);
    system("pause");
    return 0;
}

运行!神奇吧?:-)

  其实不止线程回调函数,其实只要是形如Func(void*,...)的回调函数都可以用这种方法直接使用类成员方法。(前提是第一个void*是自定义数据,也就是说它不能有其它功能)。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值