模板首个简单构造函数:
template
class Callback {
public:
/** Create a Callback with a static function
* @param func Static function to attach
*/
Callback(R (*func)() = 0) {
if (!func) {
memset(this, 0, sizeof(Callback));
} else {
generate(func);
}
}
}
在对Callback实例化时,可以不带<>模板参数,编译器可以根据Callback构造函数的入参自动补充, 比如
callback(this, &cCallBackTest::CallBackFunc);
或者如果 cCallBackDerived继承 cCallBackTest,声明一个对象如:cCallBackDerived ObjCallBackDerived;
则 callback(&ObjCallBackDerived, &cCallBackTest::CallBackFunc);
注意这里模板参数U和T是继承关系,即U继承了T,结合method_context可以清楚看到
template
Callback(U *obj, R (T::*method)()) {
generate(method_context(obj, method));
}
method_context用到了()操作符重载, 使用()时会调用obj的method
//从上面generate的调用看到,这里模板参数O为上面的T,而入参为U的obj,即T为U的基类
template
struct method_context {
M method;
O *obj;
method_context(O *obj, M method)
: method(method), obj(obj) {}
R operator()() const {
return (obj->*method)();
}
};
从上面调用可知道,generate的模板参数 F 为struct method_context, f为实例入参。 function_call为静态成员函数,具有固定函数指针入口,初始化到ops。 对本callback对象占用的内存进行清零,memset(this, 0, sizeof(Callback)); 然后该内存初始化为F(f),即已经实例化的struct method_context(上面的method_context
此时的callback内存大小应该包括method_context + _ops。
template
void generate(const F &f) {
static const ops ops = {
&Callback::function_call,
&Callback::function_move,
&Callback::function_dtor,
};
MBED_STATIC_ASSERT(sizeof(Callback) - sizeof(_ops) >= sizeof(F),
"Type F must not exceed the size of the Callback class");
memset(this, 0, sizeof(Callback));
new (this) F(f);
_ops = &ops;
}
方法call将会调用_ops->call(this); 亦即 function_call(this)
R call() const {
MBED_ASSERT(_ops);
return _ops->call(this);
}
/** Call the attached function
*/
R operator()() const {
return call();
}
function_call(this), 如function_call代码所示,入参this被强制转换为F(即struct method_context)。 return (*(F*)p)(); 展开为: (*(struct method_context *) this) 为上文中的struct method_context 实例, 而this也即是上文中method_context
R operator()() const {
return (obj->*method)();
} ,即实现了最终调用struct method_context 里的obj和method功能。
template
static R function_call(const void *p) {
return (*(F*)p)();
}
template
static void function_move(void *d, const void *p) {
new (d) F(*(F*)p);
}
template
static void function_dtor(void *p) {
((F*)p)->~F();
}
thunk 为静态成员函数,对callback 类型的func进行强制转换然后调用call,过程同上。
static R thunk(void *func) {
return static_cast(func)->call();
}
demo如下:
class cCallBackTest
{
public:
cCallBackTest(){
m_Callback = Callback(this, &cCallBackTest::CallBackFunc);
}
~cCallBackTest(){}
void CallBackFunc()
{
while (1)
{
printf("CallBackFunc~~~~~~~~~~\n\n");
}
}
void call()
{
//使用了callback的()操作符重载函数
m_Callback();
}
private:
mbed::Callback m_Callback;
};
另外,函数struct function_context的实现流程也和struct method_context 类似。 Callback 模板类使用起来比较方便,但是里面的具体实现流程比较烧脑。