C++语言中的元类编程(6)
现在是我们考虑支持切入点的时候了,结合第三篇中对切入点的讨论,在我们的meta_worker类中加入切入点的调用应该不难,只需修改say_hello_closure和meta_worker::getMethod两个函数即可:
template<typename target_traits>
struct cut_point_closure {
typedef meta_cut_point<target_traits> my_meta_cut_point;
typedef typename my_meta_cut_point::enter_point_args enter_point_args;
typedef typename my_meta_cut_point::leave_point_args leave_point_args;
enter_point_args mEnterPointArgs;
leave_point_args mLeavePointArgs;
mCutPoints[0] = NULL;
mCutPoints[1] = NULL;
mEnterPointArgs.targetArgs = NULL;
mEnterPointArgs.ignoreTarget = false;
mLeavePointArgs.enterPointArgs = &mEnterPointArgs;
mLeavePointArgs.targetRetVal = NULL;
mLeavePointArgs.error = NULL;
}
bool onEnter(meta_worker::object_data * that) {
if (mCutPoints[0]) {
mEnterPointArgs.targetArgs = that;
mCutPoints[0]->closureEntry(&mEnterPointArgs);
}}
~cut_point_closure() {
if (mCutPoints[1])
mCutPoints[1]->closureEntry(&mLeavePointArgs);
};
struct say_hello_cut_point_traits {
typedef meta_worker::object_data arg_type;
typedef void_type ret_type;
};
struct say_hello_closure: cut_point_closure<say_hello_cut_point_traits> {
meta_worker::meta_say_hello * mMetaClosure;meta_worker::meta_say_hello::arg_wrapper_type mArgWrapper;
void operator ()(meta_worker::object_data * that) {
onEnter(that);if (!mEnterPointArgs.ignoreTarget) {
mArgWrapper.args.that = that;
mMetaClosure->closureEntry(&mArgWrapper);
}
}
};
bool meta_worker::getMethod(const char * name, void * out_closure, size_t closureSize) {
if ( 0 == strcmp("sayHello", name) && sizeof(say_hello_closure) == closureSize ) {
say_hello_closure * closure = static_cast<say_hello_closure *>(out_closure);
closure->mCutPoints[0] = mEnterPoints[1];
closure->mCutPoints[1] = mLeavePoints[1];
closure->mMetaClosure = &mMetaSayHello;
return true;
} else {
// 检查名字并返回其它函数的闭包...
}
}
虽然上面的例子并不是最优的实现(有兴趣的朋友不妨自己修改看看),但不妨碍我们继续讨论。现在我们终于到了冲刺的时刻,利用切入点,我们可以很方便的在调用sayHello(...) 之前(参见上一篇中的用法示例)的任何地方实现一个切入点处理函数,并将这个函数注册到 meta_worker 中,通常我们可以利用一个函数来做这件事,然后,我们可以把这个注册切入点的函数封装到一个插件(即动态库)中,这样,当我们调试时,只需要更新这个插件就能轻松获得我们想要的日志了。具体的代码就不再演示了,有需要的朋友可以查阅一些动态库方面的资料,或者直接给我留言。
到此,我们的第一个例子问题就算解决了,最后还需要再提一点,如果你是一位熟悉设计模式的朋友,你可能认为这里采用的方法有些麻烦,在解决这个问题时的一个关键技术就是对切入点的支持,而利用设计模式中的 Agent 模式也可达到同样的效果,不是吗?我要说的是,没错,的确如此,这正应验了一句老话“条条大路通罗马”,但这里有两个事实需要说明:1)切入点的概念本来就来自于元类编程,利用 Agent 模式去实现只是实现方法不同,其思想并没有变;2)这里采用的例子只是大多数讲元类编程的(其它支持元类编程语言的)文章或书籍中都举过的例子,这里无非是为了帮助不了解元类编程的朋友理解元类的正确概念和用法。事实上我们在现实的工作中,还有很多其它的问题,当采用元类编程技术来解决就会方便得多,而这也正是我准备在下篇中重点介绍的内容。