问题的由来
C回调的步骤一般是:
- 声明callback函数类型;
- 根据类型定义一个callback函数A;
- 把定义的函数A,作为参数传入到另外一个函数B;
- 函数B会在某个时刻,调用A。
因为C里面函数定义了之后,都是一个全局变量,编译就会分配好地址,所以可以很方便的传递和使用。
但是在C++里,情况有点不一样:
C++的类成员方法即使声明定义了,如果这个类不实例化成对象,那么,类成员方法是不会有地址的,所以也就无法传递给C函数。
简单讲,就是你不能使用一个尚且还不存在东东~
那怎么办呢?
问题的解决
经过摸索,目前总结有两种方法:
一. 类成员函数声明成static函数
类的static成员讲解请看这篇:C++ 类的静态成员详细讲解
声明成static的类成员函数,简单讲,就跟C语言的全局函数是一个意思,编译阶段就确定好了内存地址,不再依赖对象而存在,因此使用起来就跟C函数是一样的,只不过要这样:类名::方法()
,要加个前缀。
在VC下的代码如下:
mythread.h
#ifndef _MY_TEST_H_
#define _MY_TEST_H_
class TestClass {
public:
TestClass();
~TestClass();
static void notify(int arg1, int arg2); // declared as static function
private:
void callback();
};
#endif
mythread.cpp:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include "mythread.h"
typedef void * HANDLE;
#define SEMAPHORE HANDLE
#define THREADHANDLE HANDLE
#define THREADPROCESS DWORD WINAPI
#define THREADRETURN 0
#define PTHREADPROCESS LPTHREAD_START_ROUTINE
#define NULLTHREAD NULL
int g_thread_end = 0;
TestClass::TestClass() {
}
TestClass::~TestClass() {
}
void TestClass::notify(int arg1, int arg2) {
printf("notify() is called!\n");
//callback(); // static function cannot call no-static function
}
void TestClass::callback() {
printf("callback() is called!\n");
}
THREADHANDLE os_creatthread(PTHREADPROCESS fun,void *para)
{
unsigned long id;
return CreateThread(NULL,0,fun,para,0,&id);
}
void waitforthread()
{
while (g_thread_end == 0)
{
NULL;
}
}
typedef void(*testCb)(int arg1, int arg2);
THREADPROCESS threadfun(PVOID arg)
{
int i;
testCb mC;
mC = (testCb)arg;
for(i=0; i < 50; i++)
{
printf("%02d: ", i);
mC(0, 0); // callback is called!
Sleep(500);
}
g_thread_end = 1;
return 0;
}
void main()
{
THREADHANDLE pthread = NULLTHREAD;
printf("Creating thread...\n");
pthread = os_creatthread(threadfun, TestClass::notify); // new a thread and register callback
printf("Creating thread completed.Handle:%x\n", pthread);
printf("Waiting for thread...\n");
waitforthread();
printf("Waiting ended.\n");
}
注释应该写的很清楚了:)
要注意的一点是:
- 静态函数是无法访问类的非静态成员的
二. 传递对象
基于一切皆对象的观点,既然不能直接传函数,那我们就传对象好了嘛~
请看代码:
mythread.h:
#ifndef _MY_TEST_H_
#define _MY_TEST_H_
class TestClass {
public:
TestClass();
~TestClass();
void notify();
private:
void callback();
};
#endif
mythread.cpp:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include "mythread.h"
typedef void * HANDLE;
#define SEMAPHORE HANDLE
#define THREADHANDLE HANDLE
#define THREADPROCESS DWORD WINAPI
#define THREADRETURN 0
#define PTHREADPROCESS LPTHREAD_START_ROUTINE
#define NULLTHREAD NULL
int g_thread_end = 0;
TestClass::TestClass() {
}
TestClass::~TestClass() {
}
void TestClass::notify() {
printf("notify() is called! -> ");
callback();
}
void TestClass::callback() {
printf("callback() is called!\n");
}
THREADHANDLE os_creatthread(PTHREADPROCESS fun,void *para)
{
unsigned long id;
return CreateThread(NULL,0,fun,para,0,&id);
}
void waitforthread()
{
while (g_thread_end == 0)
{
NULL;
}
}
THREADPROCESS threadfun(PVOID arg)
{
int i;
TestClass *mC;
mC = (TestClass *)arg;
for(i=0; i < 50; i++)
{
printf("%02d: ", i);
mC->notify(); // callback function is calling
Sleep(500);
}
g_thread_end = 1;
return 0;
}
void main()
{
THREADHANDLE pthread = NULLTHREAD;
TestClass *myClass = new TestClass(); // firstly, new an object
printf("Creating thread...\n");
pthread = os_creatthread(threadfun, myClass); // register this object as callback
printf("Creating thread completed.Handle:%x\n", pthread);
printf("Waiting for thread...\n");
waitforthread();
printf("Waiting ended.\n");
delete myClass;
}
OK,说完了,两种方法哪种更好用,我目前还挺喜欢第二种的,因为没有只能访问静态成员的限制,有了对象之后,你就可以为所欲为啦~