关闭

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

标签: c++
414人阅读 评论(0) 收藏 举报
分类:

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

猜你在找
【直播】机器学习&数据挖掘7周实训--韦玮
【套餐】系统集成项目管理工程师顺利通关--徐朋
【直播】3小时掌握Docker最佳实战-徐西宁
【套餐】机器学习系列套餐(算法+实战)--唐宇迪
【直播】计算机视觉原理及实战--屈教授
【套餐】微信订阅号+服务号Java版 v2.0--翟东平
【直播】机器学习之矩阵--黄博士
【套餐】微信订阅号+服务号Java版 v2.0--翟东平
【直播】机器学习之凸优化--马博士
【套餐】Javascript 设计模式实战--曾亮
查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:6351次
    • 积分:115
    • 等级:
    • 排名:千里之外
    • 原创:4篇
    • 转载:10篇
    • 译文:0篇
    • 评论:3条
    文章分类
    最新评论