symbian中的一些API接口都需要一个TCallBack类型的参数作为回调函数使用, 如果你需要指定到一个类的成员函数, 一般我们要写一段套路代码,
1. 先定义一个静态函数, 接收一个void*指针,
2. 然后在这个函数中将这个指针转换成某个class的指针, 然后调用class中的某个成员函数,
例如
class CFoo
{
void start_timer()
{
iTimer = CPeriodic::NewL(EPriorityLow);
iTimer->Start(5 * 1000000, 5 * 1000000, TCallBack(CFoo::entry, this); #1
}
//#2 公式化代码
static TInt entry(void * p)
{
CFoo * f = static_cast<CFoo*>(p);
return f->Timeout();
}
TInt Timeout()
{
do_sth();
return 0;
}
};
例如上面的例子, 需要启动一个Timer, 在#1处将CFoo::entry静态函数地址和一个this指针赋给TCallBack,
我们必须提供一个静态函数entry, 其中进行一个强制转换, 然后调用我们的成员函数Timeout.
#2处的套路代码写一次还可以接收, 写多了确实比较麻烦, 下面是一个我并不满意的方法可以摆脱#2.
优点是并没有动态内存分配, 在Symbian上分配内存实在是胆战心惊, 缺点是这个MemCBData需要作为一个class的成员变量.
因为在Callback发生时这个对象必须存在, 如果VC6支持成员函数作为模板参数argument, 那么MemCBData就无需作为class成员变量. 但是....
无论如何, 至少可以省写几行代码, (好像也省不了太多) , 这也就是这个class的目的.
template<class T>
struct MemCBData
{
public:
void assign(T* p, TInt (T::*mf)() )
{
this->p_ = p;
this->mf_ = mf;
}
operator TCallBack() // intended not const
{
assert(p_);
assert(mf_);
return TCallBack(&invoker, this);
}
private:
T * p_;
TInt (T::*mf_)();
static TInt invoker(void* aPtr);
TInt call()
{
return (p_->*mf_)();
}
};
template<class T>
TInt MemCBData<T>::invoker(void * ptr)
{
MemCBData * c = static_cast<MemCBData*>(ptr);
return c->call();
}
使用例子:
class CFoo
{
MemCBData<CFoo> cb1;
MemCBData<CFoo> cb2;
CPeriodic iTimer1; iTimer2;
void start_timer()
{
iTimer1 = CPeriodic::NewL(EPriorityLow);
iTimer2 = CPeriodic::NewL(EPriorityLow);
//time1 触发Timeout1 函数, time2触发Timeout2函数
cb1.assign(this, CFoo::Timeout1);
iTimer1->Start(5 * 1000000, 5 * 1000000, cb1);
cb2.assign(this, CFoo::Timeout2);
iTimer2->Start(10 * 1000000, 10 * 1000000, cb1);
}
TInt Timeout1()
{
do_sth();
return 0;
}
TInt Timeout2()
{
return 1;
}
};