引言
在.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;
}
這是一個簡單的類,它包含了一個符合函數對象要求的函數-以一個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;
return0;
}
產生結果如下:
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;
return0;
}
結果如下:
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:
virtualvoidoperator () 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 */
voidoperator ()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:
virtualvoidoperator () (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 */
voidoperator ()(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 */
};
voidoperator ()parmdecl { (m_pObj->*m_pFunc)parmcall; }
voidoperator ()(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 */
voidoperator +=(Functor *pFunc);
voidoperator +=(void (*pFunc)parmdecl);
/* Subtraction operators */
template<class C>
voidoperator -=(TFunctor<C> *pFunc);
voidoperator -=(void (*pFunc)parmdecl);
/* Calls all the callbacks in the callback list */
void Invoke parmdecl;
/* Calls all the callbacks in the callback list */
voidoperator ()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; }
virtualvoid Fun1(int val, float val2)
{
value = val*2*(int)val2;
cout << "[A::Fun1] " << val << ", " << val2 << endl;
}
staticvoid 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;
return0;
}
[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: pObj - A pointer to the object to call the callback method in the context of.
pFunc - A pointer to the callback method to call.
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: pObj - A pointer to the object that is being referred to.
pFunc - A pointer to the callback method being referred to.
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().
增加一個宏-參數化的類來支持返回類型,為委托中每個函數對象存儲返回值用以之後訪問。
加一些支持固定參數個數的模板類,如只帶一個參數的類,或只帶兩個參數的類等),這可能需要或不需要在量的類來實現-為委托的返回值或其它功能提供不同類型的類。
建議?
History
版本信息
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__
#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;
}