一个CallBack函数模板

lightnut 2007-04-30 12:09:40
工作中经常需要调用一些老的库函数, 这些库函数又常常需要提供某种
回调函数(callback).比如在oldlib.h中定义了如下的函数:

//oldlib.h
typedef double (*Func) (double);
double _mean_value(double x0, double x1, Func f);

在使用_mean_value时, 我们需要提供一个Func型的回调函数。

现在假设我们开发了某个类SomeEngine

class SomeEngine
{
public:
...........
double EngineFunction(double x)
{
return x+mX;
};
double UseMeanValue()
{
return _mean_value(0, 1, EngineFunction); //(1)
}
private:
double mX;
};

我们希望在语句(1)中调用_mean_value时传递一个成员函数作为回调函数。然而
不幸的是(1)不能通过编译。虽然EngineFunction看起来与Func具有相同的参数
和返回值, 然而实际上它们是不同的函数类型, EngineFunction隐含了一个this指针。

现在我们来考虑如何饶过这个this指针问题。我们知道类的静态成员是不含this指针
的。好象我们可以这样写:

class SomeEngine
{
public:
...........
static double sEngineFunction(double x)
{
return EngineFunction(x); //(2)
}

double EngineFunction(double x)
{
return x+mX;
}

double UseMeanValue()
{
return _mean_value(0, 1, sEngineFunction);
}
private:
double mX;
};

现在(2)不能通过编译了, 因为静态成员函数不能访问非静态成员函数。如果我们能在(2)中获得this指针就好了, 这样 return this->EngineFunction(x)就没问题了。但是 静态成员函数不含this指针呀。(这个this真是麻烦:()。

办法总是有的, 现在我们给SomeEngine添加一个静态的指向自己的指针mspTHIS:

class SomeEngine
{
public:
...........
static double sEngineFunction(double x)
{
return mspTHIS->EngineFunction(x);
}

double EngineFunction(double x)
{
return x+mX;
}

double UseMeanValue()
{
mspTHIS = this;
return _mean_value(0, 1, sEngineFunction);
mspTHIS = NULL;
}
private:
double mX;
static SomeEngine* mspTHIS;
};

SomeEngine* SomeEngine::mspTHIS = NULL;

好了, 现在编译没有问题了, 程序也能够达到我们最初的目标。 不过回头看看,
仅仅为了传一个成员函数, 我们对SomeEngine的改动也太多了点(一个静态成员函数, 一个静态指针)。如果有另一个类也需要使用调用_mean_value(), 我们又得费一翻工夫, 重复劳动了。

这回我们要动用模板了。 下面给一个模板类, 来达到同样的目的, 具体细节就
不解释了.

//================================================================
// CLASS
// CallBackFunction<T, RT, PT>
// DESCRIPTION
// This template class is used as a convient wrapper
// for passing a non-static member function to an old C routine
// which requires a callback function.
// =============================================================
template
<
typename T,
typename ReturnT,
typename ParamT
>
class CallBackFunction
{
public:
typedef ReturnT (T::*MemberCallBackFunction)(ParamT);
typedef ReturnT (*CallBackFunc) (ParamT);

CallBackFunction(T* pT, MemberCallBackFunction memberCallBack)
{
mspT = pT;
mMemberCallBack = memberCallBack;
}

~CallBackFunction()
{
mspT = NULL;
mspTHIS = NULL;
}

operator CallBackFunc()
{
mspTHIS = this;
return CallBack;
}

private:
static ReturnT CallBack(ParamT x)
{
return (mspT->*(mspTHIS->mMemberCallBack))(x);
}

MemberCallBackFunction mMemberCallBack;
static T* mspT;
static CallBackFunction* mspTHIS;

// no implementations
CallBackFunction();
CallBackFunction(const CallBackFunction& rhs);
CallBackFunction<T, ReturnT, ParamT>& operator=(CallBackFunction<T, ReturnT, ParamT>& rhs);
};

template<typename T, typename ReturnT, typename ParamT>
T* CallBackFunction<T, ReturnT, ParamT>::mspT = NULL;

template<typename T, typename ReturnT, typename ParamT>
CallBackFunction<T, ReturnT, ParamT>* CallBackFunction<T, ReturnT, ParamT>::mspTHIS=NULL;

现在回到SomeEngine类, 看看如何使用上面的CallBackFunction<>。

class SomeEngine
{
public:
...........
double EngineFunction(double x)
{
return x+mX;
};
double UseMeanValue()
{
CallBackFunction<SomeEngine, double, double> engineFunction(this, &SomeEngine::EngineFunction);
return _mean_value(0, 1, engineFunction);
}
private:
double mX;
};

与最初的的SomeEngine比, 我们只添加了一行代码。这就是变化:
return _mean_value(0, 1, EngineFunction)
======>
CallBackFunction<SomeEngine, double, double> engineFunction(this, &SomeEngine::EngineFunction);
return _mean_value(0, 1, engineFunction);
没有static函数, 没有static指针, 世界清净了; 可以在任何类中使用, 可以偷懒了:))

///ps.
如果你使用了上述模板:
1。 如果你的机器爆了, 请你不要投诉我
2。 如果你中了500万大彩, 请给CSDN捐250万
:))))))))

...全文
472 7 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
FingerStyle 2007-04-30
  • 打赏
  • 举报
回复
mark.
不想低调 2007-04-30
  • 打赏
  • 举报
回复
celftj 2007-04-30
  • 打赏
  • 举报
回复
没没看完...
taodm 2007-04-30
  • 打赏
  • 举报
回复
这个模板要想真有实用价值,代码量就是boost function库的大小,文件加起来一共62K,还不算调的boost库其它组件的大小。
lightnut 2007-04-30
  • 打赏
  • 举报
回复
我们先看看boost.function自己怎么说的:

Generally, any place in which a function pointer would be used to
defer a call or make a callback, Boost.Function can be used instead
to allow the user greater flexibility in the implementation of
the target. Targets can be any 'compatible' function object
(or function pointer), meaning that the arguments to the interface
designated by Boost.Function can be converted to the arguments
of the target function object.

很显然, boost.function的设计初衷是将它作为“目标”。 这点不太好理解。
拿楼主的例子来说, boost.function应该用的地方是_mean_value的实现自身,
也就是说_mean_value的函数原型变为这么一种形式:
_mean_value(double , double , BoostFunction)。
但是不要忘了,楼主文章的前提条件是_mean_value是原来某些C库的函数, 我们
是不可能去修改它的原型和实现的。楼主需要的是一个向后兼容的callback
模板!

那么,这是不是说boost.function不适用于楼主文章中的情况了?当然不是, 只不过
要费那么一点点手脚。

看看下面的文章, 也许你就可能知道如何用boost.function来实现楼主的需求了;)


http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?Generalizing_C-Style_Callbacks
systemthink 2007-04-30
  • 打赏
  • 举报
回复
MARK!
  • 打赏
  • 举报
回复
好麻烦啊

65,187

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧