word复制的文本有底色文字后有底色怎么去掉

怎么在线程中调用其他类非静态成员函数_读书人
怎么在线程中调用其他类非静态成员函数
&来源:读书人网&【读书人网():综合教育门户网站】
如何在线程中调用其他类非静态成员函数已知类A,类B在类C中,建立线程,函数为UINT TestFun(LPVOID lpParam){
如何在线程中调用其他类非静态成员函数已知类A,类B在类C中,建立线程,函数为UINT&TestFun(LPVOID&lpParam){&&&&访问A.funtion()}有什么办法么? 多线程 静态访问 [解决办法]创建线程TestFun的时候将A类的对象,以地址的形式赋值给lpParam,然后在TestFun中A*&pA&=&(A*)lpP转换过来。就可以调用pA-&funtion();人人网 - 抱歉
哦,抱歉,好像看不到了
现在你可以:
看看其它好友写了什么
北京千橡网景科技发展有限公司:
文网文[号··京公网安备号·甲测资字
文化部监督电子邮箱:wlwh@··
文明办网文明上网举报电话: 举报邮箱:&&&&&&&&&&&&  用我的理解通俗地解释一下什么是C++中的Thunk技术吧!  Thunk技术就是申请一段可执行的内存, 并通过手动构造CPU指令的形式来生成一个小巧的, 具有明确作用的代码块.  小巧? 具有明确作用? 你曾经初学C++时, 如果我没猜错的话, 肯定尝试过用C++封装一个窗口类(因为我也尝试过 :-) ),在封装窗口类的时候,在类内部定义一个私有(或公有)的成员函数来作为窗口回调函数, 并以CreateWindowEx(...,&MyWindowClass::WindowProc,...)的形式构造一个窗口, 可哪知, 这完全是行不通的, 因为(非静态)类成员函数的指针可不是简单的全局成员函数指针那样!
  于是, 你不得不把窗口过程定义为全局函数. 但是这样的话, 每个类都共享一个窗口过程了, 这显然不行! 于是,你可能又想到了一种算是解决办法的办法, 使用CreateWindowEx的最后一个参数LPARAM来传递this指针! 关于窗口类的封装, 这里我不再多说, 因为我打算再写一篇文章介绍用多种方法来实现窗口类的封装, 当然, 这里将要讨论的Thunk技术算是最完美的一种了! 但是,Thunk技术也不只是用于封装窗口类, 也可以用来封装线程类, etc.
  传言这种技术来自于ATL/WTL, 我不会ATL/WTL, Thunk技术是我在网上学来的.  MFC不是使用我接下来要介绍的通用(非完全)Thunk方式, 关于MFC的封装方式, 我将在另一篇文章里面提及.  这里有一篇介绍通过Thunk技术的文档:  好吧, 言归正传, 谈谈Thunk的原理与实现...  要理解Thunk的实现, 需要清楚C/C++中的函数调用约定, 如果有不懂的, 可以参考:  C++的成员函数(不讨论继承)在调用时和普通的函数并没有太大的区别, 唯一很重要的是, 需要在调用每个非静态成员函数时悄悄地传入this指针. 在类内部调用时的直接调用, 或在类外部调用时通过obj-&MemberFunction的形式调用时, 编译器都在生成代码的时候帮我们传入了this指针, 所以我们能正确访问类内部的数据.   但是, 像Windows的窗口回调函数WindowProc, 线程的回调函数ThreadProc, SQLite3的回调函数sqlite3_callback在被传给主调函数时,它们是不能被直接使用的, 因为主调函数不属于类的成员函数, 他们也没有this指针!  看看下面的代码:
    A a1,a2;
    a1.foo(1,2,3);
    a2.foo(4,5,6);
      这是我们的书写方式, 编译器在编译时将生成如下调用(只考虑__cdecl和__stdcall,没有哪一个全局函数需要__thiscall的回调):
    foo(&a1,1,2,3);
    foo(&a2,4,5,6);
    我在中已经讨论过这个东西了...  好了, 现在我们知道foo函数的原型可以是如下的形式 int __cdecl foo(int a,int b,intc);  假如我们有一个全局的函数, 她的原型是这样的:
int func( int (__cdecl*)(int,int,int) );
&  你会怎样把A类里面的foo作为回调, 传递给func?& func(&A::foo); ? 这是不可行的, 我们需要借助Thunk!
  1.下面将拿Windows中的WindowProc窗口回调函数来作具体讲解__stdcall的回调函数Thunk应用.  Windows的窗口管理在调用我们提供的全局窗口过程时, 此时的堆栈形式如下:    低 & & & & & & & & & & & & & & & & & & & & & & & 高  -----------------------------------------------------------   返回地址&&&& hWnd&&&&& uMsg&&&&&& wParam&&&&& lParam  如果我们将WindowProc定义为类成员的形式, 并在类内调用她, 则参数栈应该是如下形式(__cdecl,__stdcall):    低 & & & & & & & & & & & & & & & & & & & & & & & 高  --------------------------------------------------------------   返回地址&& & this&& hWnd&&&&& uMsg&&&&&& wParam&&&&& lParam    好了, 现在我们就可以动动手脚, 修改一下堆栈, 传入this指针, 然后就可以交给我们的成员WindowProc函数来处理啦~  我们申请一段可执行的内存, 并把他作为回调函数传递给DialogBoxParam/CreateDialogParam,(这里只讨论对话框)  申请可执行内存, 使用 VirtualAlloc    因为是WindowProc是__stdcall调用约定, 就算我们多压入了一个this参数, 也不管调用者的事, 因为堆栈是由被调用者(windowProc)来清理的. 虽然只有4个显式参数, 但作为成员函数的WindowProc在结束的时候是用ret 14h返回的, this被自动清除, 你知道为什么吗?   我们只需构造如下的3条简单的指令即可: 
machine code
assembly code
------------------------------------------------------------------------------------------
dword ptr[esp]
;再次压入返回地址
C7 44 24 04 ?? ?? ?? ??
dword ptr[esp+4],this
;修改前面那个返回地址为this指针
E9 ?? ?? ?? ??
(relative target)
;转到成员函数
  你没有看错, 真的就只需要这么几条简单的指令~~~~ :-)  2.下面再看一个__cdecl的回调函数的Thunk技术的实现    __cdecl形式的回调函数的特点:      1.参数个数比函数声明要多一个this      2.参数栈由调用者清理    我们需要以同样的方式压入this指针, 但是__cdecl约定是由调用者来清理参数栈, 我们多传了一个this指针进去, 如果直接返回,  势必会导致堆栈指针ESP错误, 所以, this指针必须由我们的程序来清除, 返回时保持被调用前一样就行了.
    作为一个完整的函数, 我们不可能在函数的最后插入一条"add esp,4"来解决问题, 这办不到.    __cdecl的Thunk的实现, 我在网上也没找到答案, 由于我汇编也不咋样, 所以搞了较长一段时间才把她搞出来~ 也算一劳永逸了.    我的处理办法(较__stdcall复杂, 但也只有几条指令而已):      1.弹出并保存原来的返回地址      2.压入this指针      3.压入我的返回地址      4.转到成员函数执行      5.清理this参数栈      6.跳转到原返回地址    汇编机器指令的实现(我并不擅长汇编, 你应该觉得还可以再优化一下):
3E 8F 05 ?? ?? ?? ??
dword ptr ds:[?? ?? ?? ??]
;弹出并保存返回地址(我的变量)
68 ?? ?? ?? ??
;压入this指针
68 ?? ?? ?? ??
;压入我的返回地址
9E ?? ?? ?? ??
(relative target)
;跳转到成员函数
;清除this栈
3E FF 25 ?? ?? ?? ??
dword ptr ds:[?? ?? ?? ??]
;转到原返回地址
  下面贴出我写的完整代码:
//Thunk.h//ts=sts=sw=4//女孩不哭
22:00//保留所有权利
#ifndef __THUNK_H__
#define __THUNK_H__
class AThunk
~AThunk();
template&typename T&
void* Stdcall(void* pThis,T mfn)
return fnStdcall(pThis,getmfn(mfn));
template&typename T&
void* Cdeclcall(void* pThis,T mfn)
return fnCdeclcall(pThis,getmfn(mfn));
typedef unsigned char
typedef unsigned short
typedef unsigned int
void* fnStdcall(void* pThis,void* mfn);
void* fnCdeclcall(void* pThis,void* mfn);
template&typename T&
void* getmfn(T t)
return u.p;
#pragma pack(push,1)
struct MCODE_STDCALL{
byte1 push[3];
struct MCODE_CDECL{
byte1 pop_ret[7];
byte1 push_this[5];
byte1 push_my_ret[5];
byte1 jmp_mfn[5];
byte1 add_esp[3];
byte1 jmp_ret[7];
byte4 ret_
#pragma pack(pop)
MCODE_CDECL
MCODE_STDCALL
#endif//!__THUNK_H__
//Thunk.cpp
//ts=sts=sw=4
//女孩不哭
//保留所有权利
#include &Windows.h&
#include "Thunk.h"
AThunk::AThunk()
m_pthis = (AThunk*)VirtualAlloc(NULL,sizeof(*this),MEM_COMMIT,PAGE_EXECUTE_READWRITE);
AThunk::~AThunk()
if(m_pthis){
VirtualFree(m_pthis,0,MEM_RELEASE);
void* AThunk::fnStdcall(void* pThis,void* mfn)
/****************************************************************************************
machine code
assembly code
------------------------------------------------------------------------------------------
dword ptr[esp]再次压入返回地址
C7 44 24 04 ?? ?? ?? ??
dword ptr[esp+4],传入this指针
E9 ?? ?? ?? ??
(relative target)转到成员函数
****************************************************************************************/
m_pthis-&m_stdcall.push[0] = 0xFF;
m_pthis-&m_stdcall.push[1] = 0x34;
m_pthis-&m_stdcall.push[2] = 0x24;
m_pthis-&m_stdcall.mov = 0x;
m_pthis-&m_stdcall.pthis = (byte4)pT
m_pthis-&m_stdcall.jmp = 0xE9;
m_pthis-&m_stdcall.addr = (byte4)mfn-((byte4)&m_pthis-&m_stdcall.jmp+5);
FlushInstructionCache(GetCurrentProcess(),&m_pthis-&m_stdcall,sizeof(m_pthis-&m_stdcall));
return &m_pthis-&m_
void* AThunk::fnCdeclcall(void* pThis,void* mfn)
/****************************************************************************************
machine code
assembly code
------------------------------------------------------------------------------------------
3E 8F 05 ?? ?? ?? ??
dword ptr ds:[?? ?? ?? ??]弹出并保存返回地址
68 ?? ?? ?? ??
压入this指针
68 ?? ?? ?? ??
压入我的返回地址
9E ?? ?? ?? ??
(relative target)跳转到成员函数
清除this栈
3E FF 25 ?? ?? ?? ??
dword ptr ds:[?? ?? ?? ??]转到原返回地址
****************************************************************************************/
m_pthis-&m_cdecl.pop_ret[0] = 0x3E;
m_pthis-&m_cdecl.pop_ret[1] = 0x8F;
m_pthis-&m_cdecl.pop_ret[2] = 0x05;
*(byte4*)&m_pthis-&m_cdecl.pop_ret[3] = (byte4)&m_pthis-&m_cdecl.ret_
m_pthis-&m_cdecl.push_this[0] = 0x68;
*(byte4*)&m_pthis-&m_cdecl.push_this[1] = (byte4)pT
m_pthis-&m_cdecl.push_my_ret[0] = 0x68;
*(byte4*)&m_pthis-&m_cdecl.push_my_ret[1] = (byte4)&m_pthis-&m_cdecl.add_esp[0];
m_pthis-&m_cdecl.jmp_mfn[0] = 0xE9;
*(byte4*)&m_pthis-&m_cdecl.jmp_mfn[1] = (byte4)mfn-((byte4)&m_pthis-&m_cdecl.jmp_mfn+5);
m_pthis-&m_cdecl.add_esp[0] = 0x83;
m_pthis-&m_cdecl.add_esp[1] = 0xC4;
m_pthis-&m_cdecl.add_esp[2] = 0x04;
m_pthis-&m_cdecl.jmp_ret[0] = 0x3E;
m_pthis-&m_cdecl.jmp_ret[1] = 0xFF;
m_pthis-&m_cdecl.jmp_ret[2] = 0x25;
*(byte4*)&m_pthis-&m_cdecl.jmp_ret[3] = (byte4)&m_pthis-&m_cdecl.ret_
FlushInstructionCache(GetCurrentProcess(),&m_pthis-&m_cdecl,sizeof(m_pthis-&m_cdecl));
return &m_pthis-&m_
  下面再贴出一篇使用示例程序, 我已经列出了我见过的常见的回调函数的使用形式:
//main.cpp
#include &iostream&
#include &Windows.h&
#include &process.h&
#include "Thunk.h"
#include "resource.h"
using namespace
/////////////////////////////////////////////////////////
//第一个:__cdecl 回调类型
/////////////////////////////////////////////////////////
typedef int (__cdecl* CB)(int n);
void output(CB cb)
for(int i=0; i&3; i++){
class ACDCEL
void* pthunk = m_Thunk.Cdeclcall(this,&ACDCEL::callback);
::output(CB(pthunk));
int __cdecl callback(int n)
cout&&"n:"&&n&&
AThunk m_T
/////////////////////////////////////////////////////////
//第二个:__stdcall 回调类型:封装窗口类
/////////////////////////////////////////////////////////
class ASTDCALL
ASTDCALL()
void* pthunk = m_Thunk.Stdcall(this,&ASTDCALL::DialogProc);
DialogBoxParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_DIALOG1),NULL,(DLGPROC)pthunk,0);
INT_PTR CALLBACK DialogProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
switch(uMsg)
case WM_CLOSE:
EndDialog(hWnd,0);
AThunk m_T
/////////////////////////////////////////////////////////
//第三个:__stdcall 回调类型:内部线程
/////////////////////////////////////////////////////////
class AThread
void* pthunk = m_Thunk.Stdcall(this,&AThread::ThreadProc);
HANDLE handle = (HANDLE)_beginthreadex(NULL,0,(unsigned int (__stdcall*)(void*))pthunk,(void*)5,0,NULL);
WaitForSingleObject(handle,INFINITE);
CloseHandle(handle);
unsigned int __stdcall ThreadProc(void* pv)
int i = (int)
while(i--){
cout&&"i="&&i&&
AThunk m_T
int main(void)
ASTDCALL as;
哎呀, 不想写了, 先去吃个宵夜, 有啥问题Q我吧~~~~全部源代码及测试下载(VC6):女孩不哭 @
22:32:25 @ /nbsofer-------------------------------
阅读(...) 评论()新手园地& & & 硬件问题Linux系统管理Linux网络问题Linux环境编程Linux桌面系统国产LinuxBSD& & & BSD文档中心AIX& & & 新手入门& & & AIX文档中心& & & 资源下载& & & Power高级应用& & & IBM存储AS400Solaris& & & Solaris文档中心HP-UX& & & HP文档中心SCO UNIX& & & SCO文档中心互操作专区IRIXTru64 UNIXMac OS X门户网站运维集群和高可用服务器应用监控和防护虚拟化技术架构设计行业应用和管理服务器及硬件技术& & & 服务器资源下载云计算& & & 云计算文档中心& & & 云计算业界& & & 云计算资源下载存储备份& & & 存储文档中心& & & 存储业界& & & 存储资源下载& & & Symantec技术交流区安全技术网络技术& & & 网络技术文档中心C/C++& & & GUI编程& & & Functional编程内核源码& & & 内核问题移动开发& & & 移动开发技术资料ShellPerlJava& & & Java文档中心PHP& & & php文档中心Python& & & Python文档中心RubyCPU与编译器嵌入式开发驱动开发Web开发VoIP开发技术MySQL& & & MySQL文档中心SybaseOraclePostgreSQLDB2Informix数据仓库与数据挖掘NoSQL技术IT业界新闻与评论IT职业生涯& & & 猎头招聘IT图书与评论& & & CU技术图书大系& & & Linux书友会二手交易下载共享Linux文档专区IT培训与认证& & & 培训交流& & & 认证培训清茶斋投资理财运动地带快乐数码摄影& & & 摄影器材& & & 摄影比赛专区IT爱车族旅游天下站务交流版主会议室博客SNS站务交流区CU活动专区& & & Power活动专区& & & 拍卖交流区频道交流区
白手起家, 积分 145, 距离下一级还需 55 积分
论坛徽章:0
我看网上说
“问题的答案是肯定的:线程函数可以是类的成员函数。但是,必须定义为类的static成员函数。”
但是我在看一项目代码时候,它的线程函数就是类的普通成员函数:
int AAA::foo(ThreadInfo *thread)
它是在Channel对象的另一个函数里作为线程函数产生线程的:
void AAA::startfoo(){
& && && && &thread.data =
& && && && &thread.func =
& && && && &if (!sys-&startThread(&thread))
& && && && && && && && &reset();
可见,其中参数Threadinfo中有个指针指向该AAA对象。
我的问题:
1.这是否就说明线程函数可以是类的非静态成员函数?
2.既然是非静态的,为什么不能直接在stream函数里调用类里的成员呢,而是要通过参数引用。 如果这个Channel是全局对象,就可以直接引用了吧,我记得线程是共享这些的
谢谢谢谢,实在没测试环境,加上好久没编程了,概念混淆还望学长指点下:)
&&nbsp|&&nbsp&&nbsp|&&nbsp&&nbsp|&&nbsp&&nbsp|&&nbsp
小富即安, 积分 4574, 距离下一级还需 426 积分
论坛徽章:212
那只是因为你的例子中是封装过的,不是原始的线程。
白手起家, 积分 29, 距离下一级还需 171 积分
论坛徽章:0
不可以,非静态成员会隐含传递一个this指针,不能做thread函数
家境小康, 积分 1058, 距离下一级还需 942 积分
论坛徽章:0
类的静态函数,本质是一个普通的函数,只不过放在这个类的名称空间下,可以访问这个类的名称空间的变量(就是静态变量)了。
因此线程的启动函数可以是类的静态函数。
白手起家, 积分 145, 距离下一级还需 55 积分
论坛徽章:0
那只是因为你的例子中是封装过的,不是原始的线程。
hellioncu 发表于
封装是因为要跨平台。而在linux下的实现就是直接调用pthread了
白手起家, 积分 145, 距离下一级还需 55 积分
论坛徽章:0
类的静态函数,本质是一个普通的函数,只不过放在这个类的名称空间下,可以访问这个类的名称空间的变量(就 ...
zzyong08 发表于
& & 我的问题是能否访问非静态函数。。
白手起家, 积分 145, 距离下一级还需 55 积分
论坛徽章:0
不可以,非静态成员会隐含传递一个this指针,不能做thread函数
sophic 发表于
& & 可是这个程序里确实是非静态的。难道是因为创建线程地方也在该类其他函数里才行的?
小富即安, 积分 4574, 距离下一级还需 426 积分
论坛徽章:212
可是这个程序里确实是非静态的。难道是因为创建线程地方也在该类其他函数里才行的?
lknh17 发表于
& & 线程入口必须是普通函数或者静态方法,当然封装的时候可以再在普通函数或者静态方法里调用特定对象的非静态成员函数
家境小康, 积分 1058, 距离下一级还需 942 积分
论坛徽章:0
& & 不能,因为非静态函数的函数类型都是void* ClassName:: (*)(void *),而不是 void * (*)(void *)。静态函数可以,因为它的函数类型是 void *(*)(void *)类成员函数作为多线程的入口函数的实现方法
我的图书馆
类成员函数作为多线程的入口函数的实现方法
通常在界面编程中,我们一方面要提供一个良好的界面环境给用户,同时后台还要做相关的应用处理,比如对数据库的查询、更新;复杂的计算处理。而这往往是很耗时的,如果界面更新和后台处理在同一个主线程中,那么界面的更新将受到后台处理程序的影响,特别是当后台程序比较耗时时,界面往往得不到及时更新,会给用户造成程序死掉的假象。对于这种情况,我们通常会采用多线程编程的方式来实现,即响应用户的操作在一个线程,而用户后台处理在另外一个线程。在有些时候,我们要新开一个线程,在这个线程里面要访问到类的成员函数和成员变量,但是CreateThread函数要求提供的线程函数必须是静态成员函数或者全局函数,这样在线程里面是不能够访问到类的成员变量的。这就是一个比较麻烦的矛盾。完整的方案如下:#include&windows.h&#include&stdio.h&#include&process.h&class test{&&&&public:&&&&test(int x):mx(x){}&&&&static unsigned int __stdcall threadProc(void* pV) { test* p = (test*)pV;&&&&&&&&p-&func();&&&&&&&&return 0;&&&&}&&&&void func()&&&&{&&&&&&&&printf("%d\n",mx);&&&&}};int main(){&&&&test x(10);&&&&_beginthreadex(0,0,test::threadProc,(void*)&x,0,0);或者m_hThread=CreateThread(NULL,NULL,CRealPlayer::MyFunction, (LPVOID)this,NULL,NULL);&&&&Sleep(100);&&&&return 0;}一种解决方案:将对象的this指针作为参数传递给线程函数,然后在线程函数里面将其转换为相应的类对象指针,在里面调用指针进行相应的操作就OK了。相应的例子如下:1.在这里创建新的线程,将this指针传递给线程函数 MyFunctionm_hThread=CreateThread(NULL,NULL,CRealPlayer::MyFunction, (LPVOID)this,NULL,NULL);2.//线程函数,在线程里面实现将CRealPlayer的member2和member3成员相加,结果放到成员member1中。这个线程函数是 static的成员函数。DWORD WINAPI CRealPlayer::MyFunction(LPVOID lpParameter){CRealPlayer * lp=(CRealPlayer *)lpPlp-&member1=lp-&member2+lp-&member3;}多线程在很多地方都有讲述,但大都作为全局函数,且不能对类的成员进行访问,本文讲述如何将一个线程定义在一个类中以及如何通过这个线程实现对类中的成员进行访问。多线程创建线程时,线程函数如果要设置成类的成员函数,则必须是静态成员函数,在此函数种不能使用非静态成员变量,如果要使用非静态成员变量,则一种比较适合线程的方法是:建立线程的时候把this作为CreateThread的一个参数(即第4个参数,就是那个LPVOID型的),然后线程里就对应pParam,例如:&&&&&&&&static UINT ThreadProc(LPVOID pParam) &&&&&&&&&{ &&&&&&&&&&&&&&&&&Your_Class *p=(Your_Class *)pP &&&&&&&&&&&&&&&&&//然后用p间接使用成员变量。&&&&&&&&&}   &&&&&&&&线程函数是回调函数,因此它必须是静态成员函数或者是类外部声明的全局函数。 函数在类中的定义在类中,多线程函数必须定义为静态函数Class CMutilThread: Public CDialog{………private:HANDLE&&&&&&&&&&hTDWORD&&&&&&&&&&&idTUINT&&&&&&&&&&&&protected:public:static&&&&&&&DWORD&&WINAPI&&ThreadPro(LPVOID lpParam);};多线程的实现多线程函数的实现(本例中每次线程被调用的时候均对计数器加1)DWORD WINAPI CMutilThread(LPVOID){CMutilThread&&*pDlg = (CMutilThread*)lpP//定义指向本类的指针,相当于this&pDlg-&couter++;&&&&//计数器加1}多线程函数的创建void CMutiThread::OnStart(){hThread = CreateThread (NULL, 0,THreadPro,this,0,idThread);}多线程的终止void CMutiThread::OnEnd(){TerminalThread(hThread,0);}//*******************************************************************************************************************************C++类成员函数直接作为线程回调函数以前写线程时要么老老实实照着声明写,要么使用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_nC&&&&int m_nId;public:&&&&TMyClass(int nId,int nCount)&&&&&&&&:m_nId(nId),m_nCount(nCount)&&&&{&&&&}&&&&void _USERENTRY ThreadProc()&&&&&&&&&&&&// 类成员方法&&&&{&&&&&&&&for(int i=0; i &m_nC 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)();&&&&} P&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&// 尽管联合里的两种函数类型现在看起来有很大不同,但它们的最终形式是相同的。&&&&TMyClass MyClass1(1,10),MyClass2(2,5); // 产生两个TMyClass对象&&&&Proc.MemberProc = &TMyClass::ThreadP&&// 转换,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*是自定义数据,也就是说它不能有其它功能)。
发表评论:
TA的最新馆藏

我要回帖

更多关于 复制的文本有底色 的文章

 

随机推荐