在C 中实现.NET风格的委托
2008-02-23 05:32:35来源:互联网 阅读 ()
在.net中,委托被用来实现事件处理。他允许一个类(方法)先注册一个事件,然后当此事件被引发时此注册的方法就会被调用。在非.Net环境的C 中,这并不是一件容易的事,尤其是类的非静态成员函数,要做为回调函数就更困难了。本文的目标就是给出一种解决方案, 使类的静态成员函数,非静态成员函数,更有类非成员函数都能像回调函数相同使用。这个实现很重视类型安全,为了保持类型安全我们省去了某些特性的实现。
什么是委托?
.NET框架中对委托的定义如下:
"委托是个能够保持对某个方法引用的类。不同于其他类,委托类有自己的签名(返回值,参数类型,个数),并且只能引用和其签名匹配的方法。委托其实能够看成一个类型安全的函数指针或回调函数。
一个提供了委托的类允许其他函数或类在此委托上注册事件处理函数。然后当这个类的委托被执行时,就会遍历其处理函数列表,逐个调用,并传入传给委托的信息。而提供委托的那个类无需知道委托注册了多少处理函数,委托自己会处理这一切。
正文
函数对象(functor)概述
我们用函数对象(functor, function object)来实现C 中的委托。这允许一个非静态成员函数能在特定对象的环境中被调用。我们用模板技术来确保任何类类型都能在其上使用。一个基本的函数对象(functor)定义如下:
template<class T> class Functor { public: // Constructor takes the values and stores them Functor(T *pObj, int (T::*pFunc)(int)) { m_pObject = pObj; m_pFunction = pFunc; } // Invokes the stored function intoperator ()(int p) { return (m_pObject->*m_pFunction)(p); } private: T *m_pObject; // Pointer to the object int (T::*m_pFunction)(int); // Pointer to the function }; |
这个函数对象(functor)使用的函数格式为:返回类型为int,带一个类型为int的参数。操作符operator ()是函数对象的关键。他使一个函数对象(functor)使用起来和函数调用相同。他的工作就是每次执行时调用保存在类内部的函数指针。以下代码展示了如何使用这个函数对象(functor):
class MyClass { public: int Square(int p) { return p * p; }; }; void some_function() { // Create a class to call in the context of MyClass theClass; // Create and initialise the functor object Functor<MyClass> myFunc(&theClass, MyClass::Square); // Call the functor using the overloaded () operator int result = myFunc(5); // result will hold the value 25 } |
由于重载了operator ()运算符,调用函数对象(functor)几乎就和调用该函数本身相同方便。这里说“几乎”是因为指向实际对象的指针并没有被显示使用-他被存放在函数对象(functor)内部使用。
的确,这很不错,但是我们为什么要使用函数对象(functor),而不是函数本身呢?很好的问题,当您知道您要调用的函数的签名(返回值和参数)而不关心其是否是类的成员函数,是哪个类的成员函数时,函数对象就很的有用(译注:将这一信息局部化在对象内部,从而以统一的方式来调用任何具备相同签名的函数)看以下代码,我将他们划分成几项以便理解:
首先,是个用纯虚基类来表示的一个以一个int为参数,返回值为int的函数对象。他只有一个函数,虚拟的operator()操作符,这样,我们就能够在不知道某函数对象实例的实际对象类型的情况下调用函数对象(functor)了.
// Abstract base class class Functor { public: // Invoke the functor (no implementation here as it must be overridden) virtualintoperator()(int) = 0; }; |
下面就是个能够被实例化为任何类类型的模板类,假设他也有一个以一个int为参数,返回为int的函数。他是从Functor派生来的,所以一个指向特定函数对象的指针能够传给任何一个需要其基类对象(Functor)指针的地方,所以此函数对象能够不管其真正的对象类型而被调用。除了基类和类名,这个类和之前给出的类是完全相同的:
// Template functor template<class T> class TemplateFunctor : public Functor { public: // Constructor takes the values and stores them TemplateFunctor(T *pObj, int (T::*pFunc)(int)) { m_pObject = pObj; m_pFunction = pFunc; } // Invokes the stored function (overrides Functor::operator ()) intoperator ()(int p) { return (m_pObject->*m_pFunction)(p); } private: T *m_pObject; // Pointer to the object int (T::*m_pFunction)(int); // Pointer to the function }; |
下面是个以函数对象指针和该函数的参数为参数的简单函数,用来调用该函数对象。注意这里以基类Functor指针而不是派生模板类指针为参数。这是必需的, 因为每一个不同的模板参数产生的模板类都是不同的类型,直接用此模板类为参数就不能支持多种类型了。
int OperateOnFunctor(int i, Functor *pFunc) { if(pFunc) return (*pFunc)(i); else return0; } |
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇: C 中通过重载避免隐式类型转换
下一篇: C 编程人员容易犯的10个C#错误
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash