9.9.7 委托和事件(3)
该示例产生下面的输出:
- Delegate with one pointer to a static function:
- Function1 called with value 90
-
- Delegate with two pointers to static functions:
- Function1 called with value 80
- Function2 called with value 80
-
- Delegate with three pointers to functions:
- Function1 called with value 70
- Function2 called with value 70
- Function3 called with value 71
-
- Shortening the invocation list...
-
- Delegate with pointers to one static and one instance function:
- Function2 called with value 60
- Function3 called with value 61
示例说明
我们在前面已经介绍过main()中出现的所有操作。我们先是显式使用Invoke()函数调用委托,然后只使用后跟实参列表的委托句柄进行调用。从输出可以看出,一切都在按照我们预期的方式工作。
虽然该示例证实委托可以包含指向单实参函数的指针,但实际上委托可以指向有任意多个实参的函数。例如,我们可以声明一个如下形式的委托类型:
- delegate void MyHandler(double x, String^ description);
该语句声明的委托类型MyHandler只能指向有两个实参、返回类型为void的函数,其中第一个实参是double类型,第二个实参是String^类型。
3. 无约束的委托
我们迄今所看到的委托都是有约束委托的示例。称之为有约束委托的原因是它们的调用列表中都有一组固定的函数。我们还可以创建无约束的委托,无约束的委托指向特定对象类型的形参列表和返回类型与委托声明一致的实例函数。因此,相同的委托可以调用指定类型的任何对象的实例函数。下面是声明无约束委托的示例:
- public delegate void UBHandler(ThisClass^, int value);
第一个参数指定this指针的类型,UBHandler类型的委托可以为该指针调用某个实例函数,该函数必须有int类型的单个形参,其返回类型必须是void。因此,UBHandler类型的委托只能为ThisClass类型的对象调用函数,但该类型的对象可以是任意一个。听起来这可能有点儿受限,但其实是非常有用的,例如,我们可以使用该委托为某个数组中ThisClass^类型的每个元素调用某个函数。
我们可以像下面这样创建UBHandler类型的委托:
- UBHandler^ ubh = gcnew UBHandler(&ThisClass::Sum);
提供给构造函数的实参是ThisClass类中形参列表和返回类型符合要求的某个函数的地址。
下面是ThisClass类的定义:
- public ref class ThisClass
- {
- public:
- void Sum(int n, String^ str)
- { Console::WriteLine(L"Sum result = {0}", value + n); }
-
- void Product(int n, String^ str)
- { Console::WriteLine(L"Product result = {0}", value*n); }
-
- ThisClass(double v) : value(v){}
- private:
- double value;
- };
Sum()函数是ThisClass类的公有实例成员,因此为该类型的任何对象调用ubh委托都将调用Sum()函数。
当我们调用某个无约束的委托时,第一个实参是调用列表内函数的当前对象,随后的实参是传递给被调用函数的实参。下面是调用ubh委托的方法:
- ThisClass^ obj = gcnew ThisClass(99.0);
- ubh(obj, 5);
第一个实参是指向某个ThisClass对象的句柄,该对象是我们通过给类的构造函数传递数值99.0而在CLR堆上创建的。该ubh调用的第二个实参是5,因此结果是以5作为实参,为obj引用的对象调用Sum()函数。
我们可以使用+运算符合并无约束的委托,从而创建一个调用多个函数的委托。当然,所有函数都必须与该委托兼容,因此就ubh委托而言,可调用的函数必须都是ThisClass类的实例函数,必须都有一个int类型的形参,返回类型为void。下面是一个示例:
- ubh += gcnew UBHandler(&ThisClass::Product);
调用ubh引用的新委托将为某个ThisClass类型的对象调用Sum()和Product()函数。让我们了解一下实际的工作情况。
试一试:使用无约束的委托
该示例使用前面的代码段,演示了无约束委托的工作情况:
- // Ex9_18.cpp : main project file.
- // Using an unbound delegate
-
- #include "stdafx.h"
-
- using namespace System;
-
- public ref class ThisClass
- {
- public:
- void Sum(int n)
- { Console::WriteLine(L"Sum result = {0} ", value+n); }
-
- void Product(int n)
- { Console::WriteLine(L"product result = {0} ", value*n); }
-
- ThisClass(double v) : value(v){}
-
- private:
- double value;
- };
-
- public delegate void UBHandler(ThisClass^, int value);
-
- int main(array<System::String ^> ^args)
- {
- array<ThisClass^>^ things = { gcnew ThisClass(5.0),
gcnew ThisClass(10.0), - gcnew ThisClass(15.0),
gcnew ThisClass(20.0), - gcnew ThisClass(25.0)
- };
-
- UBHandler^ ubh = gcnew UBHandler(&ThisClass::Sum);
-
// Create a delegate object -
- // Call the delegate for each things array element
- for each(ThisClass^ thing in things)
- ubh(thing, 3);
-
- ubh+=gcnew UBHandler(&ThisClass::Product);// Add a
function to the delegate -
- // Call the new delegate for each things array element
- for each(ThisClass^ thing in things)
- ubh(thing, 2);
-
- return 0;
- }