这几天在看C#的时候, 发现其委托这种机制非常的先进,因为自己工作中用的较多的是C++,于是便有了在C++中实现它的想法。先在网上搜了一下,便发现了这篇好文,个人觉得其实现是很“美”的,于是便翻译了过来。(欢迎批评指正)
目录
- 引言
- 什么是委托?
- 正文
- 函数对象(functor)概述
- 利用宏(macro)实现函数对象参数化
- 实现委托
- 如何使用
- 帮助
- 后续功能
- 版本信息
引言
在
.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
int
operator
()(
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)
virtual
int
operator
()(
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 ())
int
operator
()(
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
return
0
;
}
这是一个简单的类, 它包含了一个符合函数对象要求的函数-以一个
int
为参数并返回一个
int
。
注意此函数还用到了一个该类的数据成员,这说明这个回调函数实际应该是在实例对象的环境下被执行的, 所以引用同一类不同对象的函数对象会产生不同的结果:
class
ClassA
{
public
:
ClassA(
int
i) { m_Value = i; }
int
FuncA(
int
i)
{
return
(m_Value - i);
}
int
m_Value;
};
这是一个简单的程序,它创建两个引用同一类类型的函数对象的实例,针对两个同类型的不同的对象实例调用函数对象,并显示结果
.
int
main()
{
ClassA a(
20
);
ClassA b(
10
);
TemplateFunctor<ClassA> functorA(&a, ClassA::FuncA);
TemplateFunctor<ClassA> functorB(&b, ClassA::FuncA);
cout <<
"a gives the value "
<< OperateOnFunctor(
5
, &functorA) << endl;
cout <<
"b gives the value "
<< OperateOnFunctor(
5
, &functorB) << endl;
return
0
;
}
产生结果如下:
a gives the value 15
b gives the value 5
在这个例子中,两个函数对象都调用了
ClassA::FuncA
, 但是针对不同的对象
.
一个相似但又有些不同的例子是针对不同的类调用函数对象,假设我们实现了一个
ClassB
如下:
class
ClassB
{
public
:
ClassB(
int
i) { m_Value = i; }
int
FuncB(
int
i)
{
return
(m_Value + i);
// + instead of -
}
int
m_Value;
};
如果我们的
main
函数实现如下,得到的结果就会有所不同:
int
main()
{
ClassA a(
20
);
ClassB b(
10
);
TemplateFunctor<ClassA> functorA(&a, ClassA::FuncA);
TemplateFunctor<ClassB> functorB(&b, ClassB::FuncB);
cout <<
"a gives the value "
<< OperateOnFunctor(
5
, &functorA) << endl;
cout <<
"b gives the value "
<< OperateOnFunctor(
5
, &functorB) << endl;
return
0
;
}
结果如下:
a gives the value 15
b gives the value 15
这个例子中,
functorB
调用了
ClassB::FuncB
,因此结果是
(10+5)
。注意我们几乎用同样的方式把两个函数对象传给了
OperateOnFunctor)
。是基类
Functor
的设计提供了我们这种方便性。
所以函数对象是非常方便的东西,但是如果我们需要不同的参数或返回类型,我们就不得不重写这些类, 这比较头痛。幸好,我们可以利用宏的特性使这个变的简单。也许会有人说这样是过份使用宏, 但这工作的很好,而且,在模板允许我们修改函数原型前,这是唯一的解决方案
因此我们定义了以下宏:
Collapse
#define DECLARE_FUNCTOR(name, parmdecl, parmcall) /
/* A function object base class for this parameter list */
/
class
name##Functor /
{ /
public
: /
virtual
void
operator
() parmdecl =
0
; /
}; /
/
/* Template class derived from Functor for /
make class-specific function objects */
/
template
<
class
C> /
class
name##TFunctor :
public
name##Functor /
{ /
public
: /
/* Only constructor - stores the given data */
/
name##TFunctor(C* pObj,
void
(C::*pFunc)parmdecl) /
{ /
m_pObj = pObj; /
m_pFunc = pFunc; /
} /
/
/* Invokes the function object with the given parameters */
/
void
operator
()parmdecl { (m_pObj->*m_pFunc)parmcall; } /
C *m_pObj;
/* Object pointer */
/
void
(C::*m_pFunc)parmdecl;
/* Method pointer */
/
};
3
个宏参数的意义如下:
- name -函数对象的名字。Functor基类会加上“Functor“的后缀, 而模板类会加上”TFunctor“的后缀。
- parmdecl -操作符operator()的参数列表声明.列表必须包括在小括号对里面
- parmcall -传给内部函数的实参列表。以下例子可以很好的解释这两个列表的关系:
使用该宏的例子:
DECLARE_FUNCTOR(Add, (
int
p1,
int
p2), (p1, p2))
定义了一个以
2
个
int
为参数函数对象
AddFunctor
。宏展开后代码如下(
当然, 事实上它们应该在一行上,并且没有注释
)
Collapse
/* A function object base class for this parameter list */
class
AddFunctor
{
public
:
virtual
void
operator
() (
int
p1,
int
p2) =
0
;
};
/* Template class derived from AddFunctor for
make class-specific function objects */
template
<
class
C>
class
AddTFunctor :
public
AddFunctor
{
public
:
/* Only constructor - stores the given data */
AddTFunctor(C* pObj,
void
(C::*pFunc)(
int
p1,
int
p2))
{
m_pObj = pObj;
m_pFunc = pFunc;
}
/* Invokes the function object with the given parameters */
void
operator
()(
int
p1,
int
p2) { (m_pObj->*m_pFunc)(p1, p2); }
C *m_pObj;
/* Object pointer */
void
(C::*m_pFunc)(
int
p1,
int
p2);
/* Method pointer */
};
正如你所看到的,在所有
name
出现的地方都被“
Add
“所代替,
parmdecl
则被
(int P1, int p2)
替换, 而
parmcall
则被
(p1, p2)
替换
)
。
为了更好的体现
parmdecl
和
parmcall
的关系,看以下
operator()
操作符,第一行是宏, 第二行是展开后的代码
:
void
operator
()parmdecl { (m_pObj->*m_pFunc)parmcall; }
void
operator
()(
int
p1,
int
p2) { (m_pObj->*m_pFunc)(p1, p2); }
parmdecl
是函数参数列表的声明,而
parmcall
是函数调用时的实参
.
遗憾的是,我们没有办法用宏来自动生成这些
.
这种实现有些不是那么优雅
,
但它可以很好的工作,并且保证了函数的类型安全
委托的实现类似于函数对象,但委托存储了一个函数对象的列表,当委托被调用时就会遍历调用这个列表中的函数对象,而不是只有一个函数对象。这意味着如果需要的话,我们可以存储,调用多个处理函数。类的定义如下(没有包括实现代码)。我没有加入
functor
的定义因为上面已经定义过了。函数对象实际上也会在这个宏当中定义,在这个名字空间中:
Collapse
#define DECLARE_DELEGATE(name, parmdecl, parmcall) /
namespace
name##Delegate /
{ /
class
Delegate /
{ /
public
: /
Delegate(); /
~Delegate(); /
/
/* Template function for adding member function callbacks */
/
template
<
class
C> /
void
Add(C *pObj,
void
(C::*pFunc)parmdecl); /
/* Add a non-member (or static member) callback function */
/
void
Add(
void
(*pFunc)parmdecl); /
/* Template function for removing member function callbacks */
/
template
<
class
C> /
void
Remove(C *pObj,
void
(C::*pFunc)parmdecl); /
/* Removes a non-member (or static member) callback function */
/
void
Remove(
void
(*pFunc)parmdecl); /
/
/* Addition operators */
/
void
operator
+=(Functor *pFunc); /
void
operator
+=(
void
(*pFunc)parmdecl); /
/* Subtraction operators */
/
template
<
class
C> /
void
operator
-=(TFunctor<C> *pFunc); /
void
operator
-=(
void
(*pFunc)parmdecl); /
/
/* Calls all the callbacks in the callback list */
/
void
Invoke parmdecl; /
/* Calls all the callbacks in the callback list */
/
void
operator
()parmdecl; /
/
private
: /
/* List of callback functions */
/
std::vector<Functor*> m_pFuncs; /
/* typedef'd iterator */
/
typedef
std::vector<Functor*>::iterator vit; /
}; /
}
一些重点
- 委托和函数对象类都放在它们自己的名字空间中,所以它们是一个易管理的整体
- 函数对象存在一个STL vector中。vector包含了指向基类Functor的指针,所以它可以包含任何类型的模板函数对象的实例。当然, 还有一个函数对象没有被列出来,这是用来包装非类成成员函数或类的静态成员函数的。它们功能上大致相同,只是它不需要保存一个对象指针,或要求函数是类的一部份
- 我们有两种方法来调用委托的函数对象-Invoke函数或operator()操作符.两种方法的效果完全相同,实际上()操作符内部调用了Invoke来实现
- 有两种方法从委托增加,删除回调函数.用Add()/Remove方法,或者用+=/-=运算符。同Invoke()/operator()一样,这两种方法在功能上相同-操作符直接调用非操作符方法。这两种方法均有两个重载,一个用来接收非静态类成员函数, 一个用来接收非类成员函数或者类静态成员函数。
还有一个用来创建函数对象的非成员函数没有列出来,其创建出来的对象用来传给
+=
和
-=
操作符函数。此函数并没有被放在该类所在的名字空间中,其名字为传给宏
DECLARE_DELEGATE
的
name
加上“
Handler
“的后缀,例如:
DECLARE_DELEGATE(Add, (
int
p1,
int
p2), (p1, p2))
将会给出如下的函数原型:
template
<
class
C>
AddDelegate::TFunctor<C> *AddHandler(C *pObj,
void
(C::*pFunc)(
int
p1,
int
p2));
展示如何使用这些代码的最好方法就是给出一个例子。以下例子定义了一个以
int, float
为参数的委托。并定义了两个简单的类和其相应函数,当然, 也使用了一个静态成员函数与一个非成员函数
Collapse
DECLARE_DELEGATE(Add, (
int
p1,
float
p2), (p1, p2))
class
A
{
public
:
A() { value =
5
; }
virtual
void
Fun1(
int
val,
float
val2)
{
value = val*
2
*(
int
)val2;
cout <<
"[A::Fun1] "
<< val <<
", "
<< val2 << endl;
}
static
void
StaticFunc(
int
val,
float
val2)
{
cout <<
"[A::StaticFunc] "
<< val <<
", "
<< val2 << endl;
}
public
:
int
value;
};
class
B :
public
A
{
public
:
void
Fun1(
int
val,
float
val2)
{
value += val*
3
*(
int
)val2;
cout <<
"[B::Fun1] "
<< val <<
", "
<< val2 << endl;
}
};
void
GlobalFunc(
int
val,
float
val2)
{
cout <<
"[GlobalFunc] "
<< val <<
", "
<< val2 << endl;
}
int
main()
{
// Create class instances
A a;
B b;
// Create an instance of the delegate
AddDelegate::Delegate del;
// Add our handlers
del += AddHandler(&a, A::Fun1);
// or del.Add(&a, A::Fun1);
del += AddHandler(&b, B::Fun1);
// or del.Add(&b, B::Fun2);
del += GlobalFunc;
// or del.Add(GlobalFunc);
del += A::StaticFunc;
// or del.Add(A::StaticFunc);
// Invoke the delegate
del(
4
,
5
);
// or del.Invoke(4, 5);
// Print the class values
cout <<
"[main] a.value = "
<< a.value << endl;
cout <<
"[main] b.value = "
<< b.value << endl;
// Remove some of the handlers
del -= AddHandler(&a, A::Fun1);
// or del.Remove(&a, A::Fun1);
del -= A::StaticFunc;
// or del.Remove(A::StaticFunc);
// Invoke the delegate again
del(
4
,
5
);
// or del.Invoke(4, 5);
// Print the class values
cout <<
"[main] a.value = "
<< a.value << endl;
cout <<
"[main] b.value = "
<< b.value << endl;
return
0
;
}
这个例子展示了委托几乎所有的操作,其结果如下:
[A::Fun1] 4, 5
[B::Fun1] 4, 5
[GlobalFunc] 4, 5
[A::StaticFunc] 4, 5
[main] a.value = 40
[main] a.value = 65
[B::Fun1] 4, 5
[GlobalFunc] 4, 5
[main] a.value = 40
[main] b.value = 125
代码用了
stl.h
文件(由
Oskar Weiland
编写)来去除编译
stl
时的警告信息,这个文件包含在
zip
文件中,当然也可以从这儿得到。可下载的代码包括
delegate.h
和以上给出的例子代码
因为代码是由
DECLARE_DELEGATE
定制的, 这里我用
<parameters>
来表示你传入的参数)
Method:
|
template
<
class
C>
void
Delegate::Add(C *pObj,
void
(C::*pFunc)(<parameters>))
|
Description:
|
Adds a callback function that is a non-static member function of a class. The member function must return
void
and take a parameter list that is the same as
<parameters>
.
|
Return value:
|
void
- nothing.
|
Parameters:
|
|
Method:
|
void
Delegate::Add(
void
(*pFunc)(<parameters>))
|
Description:
|
Adds a callback function that is either a static member function of a class or is not a class member function. The function must return
void
and take a parameter list that is the same as
<parameters>
.
|
Return value:
|
void
- nothing.
|
Parameters:
|
pFunc
- A pointer to the callback function to call.
|
Method:
|
template
<
class
C>
void
Delegate::Remove(C *pObj,
void
(C::*pFunc)parmdecl)
|
Description:
|
Removes a callback function from the callback function list
|
Return value:
|
void
- nothing.
|
Parameters:
|
These two parameters together specify the callback handler to be removed.
|
Method:
|
void
Delegate::Remove(
void
(*pFunc)parmdecl)
|
Description:
|
Removes a callback function from the callback function list
|
Return value:
|
void
- nothing.
|
Parameters:
|
pFunc
- A pointer to the callback method being referred to.
|
Method:
|
void
Delegate::
operator
+=(Functor *pFunc)
|
Description:
|
Adds a callback function that is a non-static member function of a class. The member function must return
void
and take a parameter list that is the same as
<parameters>
.
|
Return value:
|
void
- nothing.
|
Parameters:
|
pFunc
- A pointer to the functor to call. This should be created using the
<name>Handler()
function.
|
Method:
|
void
Delegate::
operator
+=(
void
(*pFunc)(<parameters>))
|
Description:
|
Adds a callback function that is either a static member function of a class or is not a class member function. The function must return
void
and take a parameter list that is the same as
<parameters>
.
|
Return value:
|
void
- nothing.
|
Parameters:
|
pFunc
- A pointer to the callback function to call.
|
Method:
|
void
Delegate::
operator
-=(Functor *pFunc)
|
Description:
|
Removes a callback function that is a non-static member function of a class.
|
Return value:
|
void
- nothing.
|
Parameters:
|
pFunc
- A pointer to the functor to remove. This should be created using the
<name>Handler()
function, and is deleted by the function.
|
Method:
|
void
Delegate::
operator
-=(
void
(*pFunc)(<parameters>))
|
Description:
|
Removes a callback function that is either a static member function of a class or is not a class member function.
|
Return Value:
|
void
- nothing.
|
Parameters:
|
pFunc
- A pointer to the callback function to remove.
|
Method:
|
void
Delegate::Invoke(<parameters>)
|
Description:
|
Calls all the callbacks in the callback list with the specified parameters.
|
Return Value:
|
void
- nothing.
|
Parameters:
|
<parameters>
- The parameters to pass to the callback functions, as specified in the parameter to
DECLARE_DELEGATE()
.
|
Method:
|
void
Delegate::
operator
()(<parameters>)
|
Description:
|
Calls all the callbacks in the callback list with the specified parameters
|
Return Value:
|
void
- nothing.
|
Parameters:
|
<parameters>
- The parameters to pass to the callback functions, as specified in the parameter to
DECLARE_DELEGATE()
.
|
- 增加一个宏-参数化的类来支持返回类型,为委托中每个函数对象存储返回值用以之后访问
- 加一些支持固定参数个数的模板类,如只带一个参数的类,或只带两个参数的类等),这可能需要或不需要在量的类来实现-为委托的返回值或其它功能提供不同类型的类
- 建议?
版本信息
- 2003-8-19-初始版本
代码文件
///
// delegate.h
// Interface/implementation of the delegate classes and macros
///
// Author: Ryan Binns
// Changelog:
// 19-Aug-2003 : Initial Release
///
#ifndef DELEGATE_H__
#define DELEGATE_H__
// This STL include file removes the STL warning when the compiler
// is set to warning level 4. It was written by Oskar Wieland, and
// is available at:
// http://www.codeproject.com/vcpp/stl/stl_without_warnings.asp
#define STL_USING_VECTOR
/*
* Here, for convenience, I just ignore this header file but put the code directly.
*/
// #include "stl.h"
#ifdef STL_USING_VECTOR
#pragma warning(push)
#include < yvals.h > // warning numbers get enabled in yvals.h
#pragma warning(disable: 4018) // signed/unsigned mismatch
#pragma warning(disable: 4100) // unreferenced formal parameter
#pragma warning(disable: 4245) // conversion from 'type1' to 'type2', signed/unsigned mismatch
#pragma warning(disable: 4663) // C++ language change: to explicitly specialize class template 'vector'
#pragma warning(disable: 4702) // unreachable code
#pragma warning(disable: 4710) // 'function' : function not inlined
#pragma warning(disable: 4786) // identifier was truncated to 'number' characters in the debug information
#include < vector >
#pragma warning(pop)
#endif
// Declares a delegate
// name - gives the beginning of the name of the delegate namespace, so
// DECLARE_DELEGATE(Add, ..., ...) would make a namespace
// called "AddDelegate" which contains the Add delegate classes.
// parmdecl - is the declaration of the parameters in the callbacks
// (surrounded by brackets), such as "(int val1, int val2)"
// parmcall - is how the parameters are called (surrounded in brackets),
// such as "(var1, var2)"
// so: DECLARE_DELEGATE(Add, (int val1, int val2), (val1, val2))
// would declare a delegate called AddDelegate, that takes two int
// parameters (the parameter names are not important).
#define DECLARE_DELEGATE(name, parmdecl, parmcall)
namespace name##Delegate
{
class Delegate; /* Forward declaration */
/* A function object base class for this parameter list */
class Functor
{
public :
virtual void Invoke parmdecl = 0 ;
virtual bool isMethod() = 0 ;
virtual bool operator == (Functor * pf) = 0 ;
};
/* Template class derived from Functor for
making class-specific function objects */
template < class C >
class TFunctor : public Functor
{
public :
/* Only constructor - stores the given data */
TFunctor(C * pObj, void (C:: * pFunc)parmdecl)
{
m_pObj = pObj;
m_pFunc = pFunc;
}
bool isMethod() { return true ; }
bool operator == (Functor * pf)
{
if ( ! pf -> isMethod())
return false ;
TFunctor < C > * pf1 = (TFunctor < C >* )pf;
if ((pf1 -> m_pObj == m_pObj) && (pf1 -> m_pFunc == m_pFunc))
return true ;
else
return false ;
}
/* Invokes the function object with the given parameters */
void Invoke parmdecl { (m_pObj ->* m_pFunc)parmcall; }
private :
C * m_pObj; /* Object pointer */
void (C:: * m_pFunc)parmdecl; /* Method pointer */
};
/* Class for function function objects */
class FFunctor : public Functor
{
public :
/* Only constructor - stores the given data */
FFunctor( void ( * pFunc)parmdecl) { m_pFunc = pFunc; }
bool isMethod() { return false ; }
bool operator == (Functor * pf)
{
if (pf -> isMethod())
return false ;
FFunctor * pf1 = (FFunctor * )pf;
if (pf1 -> m_pFunc == m_pFunc)
return true ;
else
return false ;
}
/* Invokes the function object with the given parameters */
void Invoke parmdecl { m_pFunc parmcall; }
private :
void ( * m_pFunc)parmdecl; /* Function pointer */
};
/* Delegate class definition */
class Delegate
{
public :
Delegate() { };
~ Delegate()
{
for (vit i = m_pFuncs.begin(); i != m_pFuncs.end(); i ++ )
delete ( * i);
m_pFuncs.clear();
}
/* Template function for adding member function callbacks */
template < class C >
void Add(C * pObj, void (C:: * pFunc)parmdecl)
{
m_pFuncs.push_back( new TFunctor < C > (pObj, pFunc));
}
/* Add a non-member (or static member) callback function */
void Add( void ( * pFunc)parmdecl)
{
m_pFuncs.push_back( new FFunctor(pFunc));
}
/* Template function for removing member function callbacks */
template < class C >
void Remove(C * pObj, void (C:: * pFunc)parmdecl)
{
TFunctor < C > f(pObj, pFunc);
for (vit i = m_pFuncs.begin(); i != m_pFuncs.end(); i ++ )
{
if ( * ( * i) == & f)
{
delete * i;
m_pFuncs.erase(i);
break ;
}
}
}
/* Removes a non-member (or static member) callback function */
void Remove( void ( * pFunc)parmdecl)
{
FFunctor f(pFunc);
for (vit i = m_pFuncs.begin(); i != m_pFuncs.end(); i ++ )
{
if ( * ( * i) == & f)
{
delete * i;
m_pFuncs.erase(i);
break ;
}
}
}
/* Addition operators */
void operator += (Functor * pFunc)
{
m_pFuncs.push_back(pFunc);
}
void operator += ( void ( * pFunc)parmdecl)
{
m_pFuncs.push_back( new FFunctor(pFunc));
}
/* Subtraction operators */
void operator -= (Functor * pFunc)
{
for (vit i = m_pFuncs.begin(); i != m_pFuncs.end(); i ++ )
{
if ( * ( * i) == pFunc)
{
delete * i;
m_pFuncs.erase(i);
break ;
}
}
delete pFunc;
}
void operator -= ( void ( * pFunc)parmdecl)
{
Remove(pFunc);
}
/* Calls all the callbacks in the callback list */
void Invoke parmdecl
{
for (vit i = m_pFuncs.begin(); i != m_pFuncs.end(); i ++ )
( * i) -> Invoke parmcall;
}
/* Calls all the callbacks in the callback list */
void operator ()parmdecl { Invoke parmcall; }
private :
/* List of callback functions */
std::vector < Functor *> m_pFuncs;
/* typedef'd iterator */
typedef std::vector < Functor *> ::iterator vit;
};
}
template < class C >
name##Delegate::TFunctor < C > * name##Handler(C * pObj, void (C:: * pFunc)parmdecl)
{
return new name##Delegate::TFunctor < C > (pObj, pFunc);
}
#endif // DELEGATE_H__
// delegate.h
// Interface/implementation of the delegate classes and macros
///
// Author: Ryan Binns
// Changelog:
// 19-Aug-2003 : Initial Release
///
#ifndef DELEGATE_H__
#define DELEGATE_H__
// This STL include file removes the STL warning when the compiler
// is set to warning level 4. It was written by Oskar Wieland, and
// is available at:
// http://www.codeproject.com/vcpp/stl/stl_without_warnings.asp
#define STL_USING_VECTOR
/*
* Here, for convenience, I just ignore this header file but put the code directly.
*/
// #include "stl.h"
#ifdef STL_USING_VECTOR
#pragma warning(push)
#include < yvals.h > // warning numbers get enabled in yvals.h
#pragma warning(disable: 4018) // signed/unsigned mismatch
#pragma warning(disable: 4100) // unreferenced formal parameter
#pragma warning(disable: 4245) // conversion from 'type1' to 'type2', signed/unsigned mismatch
#pragma warning(disable: 4663) // C++ language change: to explicitly specialize class template 'vector'
#pragma warning(disable: 4702) // unreachable code
#pragma warning(disable: 4710) // 'function' : function not inlined
#pragma warning(disable: 4786) // identifier was truncated to 'number' characters in the debug information
#include < vector >
#pragma warning(pop)
#endif
// Declares a delegate
// name - gives the beginning of the name of the delegate namespace, so
// DECLARE_DELEGATE(Add, ..., ...) would make a namespace
// called "AddDelegate" which contains the Add delegate classes.
// parmdecl - is the declaration of the parameters in the callbacks
// (surrounded by brackets), such as "(int val1, int val2)"
// parmcall - is how the parameters are called (surrounded in brackets),
// such as "(var1, var2)"
// so: DECLARE_DELEGATE(Add, (int val1, int val2), (val1, val2))
// would declare a delegate called AddDelegate, that takes two int
// parameters (the parameter names are not important).
#define DECLARE_DELEGATE(name, parmdecl, parmcall)
namespace name##Delegate
{
class Delegate; /* Forward declaration */
/* A function object base class for this parameter list */
class Functor
{
public :
virtual void Invoke parmdecl = 0 ;
virtual bool isMethod() = 0 ;
virtual bool operator == (Functor * pf) = 0 ;
};
/* Template class derived from Functor for
making class-specific function objects */
template < class C >
class TFunctor : public Functor
{
public :
/* Only constructor - stores the given data */
TFunctor(C * pObj, void (C:: * pFunc)parmdecl)
{
m_pObj = pObj;
m_pFunc = pFunc;
}
bool isMethod() { return true ; }
bool operator == (Functor * pf)
{
if ( ! pf -> isMethod())
return false ;
TFunctor < C > * pf1 = (TFunctor < C >* )pf;
if ((pf1 -> m_pObj == m_pObj) && (pf1 -> m_pFunc == m_pFunc))
return true ;
else
return false ;
}
/* Invokes the function object with the given parameters */
void Invoke parmdecl { (m_pObj ->* m_pFunc)parmcall; }
private :
C * m_pObj; /* Object pointer */
void (C:: * m_pFunc)parmdecl; /* Method pointer */
};
/* Class for function function objects */
class FFunctor : public Functor
{
public :
/* Only constructor - stores the given data */
FFunctor( void ( * pFunc)parmdecl) { m_pFunc = pFunc; }
bool isMethod() { return false ; }
bool operator == (Functor * pf)
{
if (pf -> isMethod())
return false ;
FFunctor * pf1 = (FFunctor * )pf;
if (pf1 -> m_pFunc == m_pFunc)
return true ;
else
return false ;
}
/* Invokes the function object with the given parameters */
void Invoke parmdecl { m_pFunc parmcall; }
private :
void ( * m_pFunc)parmdecl; /* Function pointer */
};
/* Delegate class definition */
class Delegate
{
public :
Delegate() { };
~ Delegate()
{
for (vit i = m_pFuncs.begin(); i != m_pFuncs.end(); i ++ )
delete ( * i);
m_pFuncs.clear();
}
/* Template function for adding member function callbacks */
template < class C >
void Add(C * pObj, void (C:: * pFunc)parmdecl)
{
m_pFuncs.push_back( new TFunctor < C > (pObj, pFunc));
}
/* Add a non-member (or static member) callback function */
void Add( void ( * pFunc)parmdecl)
{
m_pFuncs.push_back( new FFunctor(pFunc));
}
/* Template function for removing member function callbacks */
template < class C >
void Remove(C * pObj, void (C:: * pFunc)parmdecl)
{
TFunctor < C > f(pObj, pFunc);
for (vit i = m_pFuncs.begin(); i != m_pFuncs.end(); i ++ )
{
if ( * ( * i) == & f)
{
delete * i;
m_pFuncs.erase(i);
break ;
}
}
}
/* Removes a non-member (or static member) callback function */
void Remove( void ( * pFunc)parmdecl)
{
FFunctor f(pFunc);
for (vit i = m_pFuncs.begin(); i != m_pFuncs.end(); i ++ )
{
if ( * ( * i) == & f)
{
delete * i;
m_pFuncs.erase(i);
break ;
}
}
}
/* Addition operators */
void operator += (Functor * pFunc)
{
m_pFuncs.push_back(pFunc);
}
void operator += ( void ( * pFunc)parmdecl)
{
m_pFuncs.push_back( new FFunctor(pFunc));
}
/* Subtraction operators */
void operator -= (Functor * pFunc)
{
for (vit i = m_pFuncs.begin(); i != m_pFuncs.end(); i ++ )
{
if ( * ( * i) == pFunc)
{
delete * i;
m_pFuncs.erase(i);
break ;
}
}
delete pFunc;
}
void operator -= ( void ( * pFunc)parmdecl)
{
Remove(pFunc);
}
/* Calls all the callbacks in the callback list */
void Invoke parmdecl
{
for (vit i = m_pFuncs.begin(); i != m_pFuncs.end(); i ++ )
( * i) -> Invoke parmcall;
}
/* Calls all the callbacks in the callback list */
void operator ()parmdecl { Invoke parmcall; }
private :
/* List of callback functions */
std::vector < Functor *> m_pFuncs;
/* typedef'd iterator */
typedef std::vector < Functor *> ::iterator vit;
};
}
template < class C >
name##Delegate::TFunctor < C > * name##Handler(C * pObj, void (C:: * pFunc)parmdecl)
{
return new name##Delegate::TFunctor < C > (pObj, pFunc);
}
#endif // DELEGATE_H__
#include
<
iostream
>
#include " delegate.h "
using namespace std;
DECLARE_DELEGATE(Add, ( int p1, float p2), (p1, p2))
class A
{
public :
A() { value = 5 ; }
virtual void Fun1( int val, float val2)
{
value = val * 2 * ( int )val2;
cout << " [A::Fun1] " << val << " , " << val2 << endl;
}
static void StaticFunc( int val, float val2)
{
cout << " [A::StaticFunc] " << val << " , " << val2 << endl;
}
public :
int value;
};
class B : public A
{
public :
void Fun1( int val, float val2)
{
value += val * 3 * ( int )val2;
cout << " [B::Fun1] " << val << " , " << val2 << endl;
}
};
void GlobalFunc( int val, float val2)
{
cout << " [GlobalFunc] " << val << " , " << val2 << endl;
}
unsigned int WinSize(unsigned char * ColCnt,
unsigned char * RowCnt)
{
unsigned short result;
__asm {
mov ax, 1416h
int 10h
mov result, cx
les edi, ColCnt
mov es:[edi], bl // error illegal reference to 16-bit data in 'first operand’
les di, RowCnt
mov es:[edi], bh // the same problem
}
return (result);
}
int main()
{
// Create class instances
A a;
B b;
// Create an instance of the delegate
AddDelegate::Delegate del;
// Add our handlers
del += AddHandler( & a, & A::Fun1); // or del.Add(&a, A::Fun1);
del += AddHandler( & b, & B::Fun1); // or del.Add(&b, B::Fun2);
del += GlobalFunc; // or del.Add(GlobalFunc);
del += A::StaticFunc; // or del.Add(A::StaticFunc);
// Invoke the delegate
del( 4 , 5 ); // or del.Invoke(4, 5);
// Print the class values
cout << " [main] a.value = " << a.value << endl;
cout << " [main] b.value = " << b.value << endl;
// Remove some of the handlers
del -= AddHandler( & a, & A::Fun1); // or del.Remove(&a, A::Fun1);
del -= A::StaticFunc; // or del.Remove(A::StaticFunc);
// Invoke the delegate again
del( 4 , 5 ); // or del.Invoke(4, 5);
// Print the class values
cout << " [main] a.value = " << a.value << endl;
cout << " [main] b.value = " << b.value << endl;
return 0 ;
}
#include " delegate.h "
using namespace std;
DECLARE_DELEGATE(Add, ( int p1, float p2), (p1, p2))
class A
{
public :
A() { value = 5 ; }
virtual void Fun1( int val, float val2)
{
value = val * 2 * ( int )val2;
cout << " [A::Fun1] " << val << " , " << val2 << endl;
}
static void StaticFunc( int val, float val2)
{
cout << " [A::StaticFunc] " << val << " , " << val2 << endl;
}
public :
int value;
};
class B : public A
{
public :
void Fun1( int val, float val2)
{
value += val * 3 * ( int )val2;
cout << " [B::Fun1] " << val << " , " << val2 << endl;
}
};
void GlobalFunc( int val, float val2)
{
cout << " [GlobalFunc] " << val << " , " << val2 << endl;
}
unsigned int WinSize(unsigned char * ColCnt,
unsigned char * RowCnt)
{
unsigned short result;
__asm {
mov ax, 1416h
int 10h
mov result, cx
les edi, ColCnt
mov es:[edi], bl // error illegal reference to 16-bit data in 'first operand’
les di, RowCnt
mov es:[edi], bh // the same problem
}
return (result);
}
int main()
{
// Create class instances
A a;
B b;
// Create an instance of the delegate
AddDelegate::Delegate del;
// Add our handlers
del += AddHandler( & a, & A::Fun1); // or del.Add(&a, A::Fun1);
del += AddHandler( & b, & B::Fun1); // or del.Add(&b, B::Fun2);
del += GlobalFunc; // or del.Add(GlobalFunc);
del += A::StaticFunc; // or del.Add(A::StaticFunc);
// Invoke the delegate
del( 4 , 5 ); // or del.Invoke(4, 5);
// Print the class values
cout << " [main] a.value = " << a.value << endl;
cout << " [main] b.value = " << b.value << endl;
// Remove some of the handlers
del -= AddHandler( & a, & A::Fun1); // or del.Remove(&a, A::Fun1);
del -= A::StaticFunc; // or del.Remove(A::StaticFunc);
// Invoke the delegate again
del( 4 , 5 ); // or del.Invoke(4, 5);
// Print the class values
cout << " [main] a.value = " << a.value << endl;
cout << " [main] b.value = " << b.value << endl;
return 0 ;
}