9.9.7 委托和事件(4)
该示例产生下面的输出:
- Sum result = 8
- Sum result = 13
- Sum result = 18
- Sum result = 23
- Sum result = 28
- Sum result = 7
- product result = 10
- Sum result = 12
- product result = 20
- Sum result = 17
- product result = 30
- Sum result = 22
- product result = 40
- Sum result = 27
- product result = 50
示例说明
UBHandler委托类型是用下面的语句声明的:
- public delegate void UBHandler(ThisClass^, int value);
UBHandler委托对象是无约束的委托,可以为ThisClass类型的对象调用实例函数,前提是被调用函数有单个int类型的形参,且返回类型为void。
该示例的ThisClass类定义与以前相同,有两个实例函数Sum()和Product(),它们的形参类型为int,返回类型为void,因此都可以被UBHandler类型的委托调用。
在main()函数中,我们用下面这条语句创建了一个指向ThisClass对象的句柄数组。
- array<ThisClass^>^ things ={gcnew ThisClass(5.0),gcnew ThisClass(10.0),
- gcnew ThisClass(15.0),
gcnew ThisClass(20.0), - gcnew ThisClass(25.0)
- };
初始化列表中的5个对象各自封装了一个彼此不同的double类型数值,这样将使我们易于在输出中识别调用Sum()和Product()函数的是哪个对象。
我们用下面的语句创建了一个委托对象:
- UBHandler^ ubh=gcnew UBHandler(&ThisClass::Sum);//
Create a delegate object
调用ubh句柄引用的委托对象,将为任何ThisClass类型的对象调用Sum()函数,我们为things数组中的每个对象都进行了该操作:
- for each(ThisClass^ thing in things)
- ubh(thing, 3);
这里的for each循环迭代经过things数组的每个元素,因此在循环体中,我们以该数组的元素作为第一个实参来调用ubh委托,结果就是thing对象的Sum()函数被调用,函数参数是3。因此,该循环产生前5行输出。
接下来,我们创建了一个新委托:
- ubh += gcnew UBHandler(&ThisClass::Product);
// Add a function to the delegate
该语句创建一个新的指向Product()函数的UBHandler委托,然后将新委托与ubh引用的现有委托合并,合并结果是另一个委托,该委托包含的指针指向其调用列表中的Sum()和Product()这两个函数。
最后一个循环以数值2为实参,为things数组中的每个元素调用ubh委托。结果将是以数值2为实参,为每个ThisClass对象调用Sum()和Product()两个函数,因此该循环产生后面的10行输出。
虽然我们以非常简单的方式使用了无约束的委托,但它们在这里给程序提供了无限的灵活性。例如,我们可以将无约束的委托作为实参传递给某个函数,以允许相同的函数在不同的时间调用不同的实例函数组合,这样该委托就成为一种函数选择器。委托调用函数的顺序与函数出现在调用列表中的顺序相同,因此委托给我们提供了控制函数调用顺序的手段。
4. 创建事件
前面曾说过,发出某个事件发生的信号需要使用委托,该委托应该包含该事件发生时将被调用的函数的指针。我们要在程序中处理的大多数事件都与按钮或菜单项这样的控件有关,这些事件源于用户与程序的交互作用,但我们也可以在自己的程序代码中定义和触发事件。
事件是使用event关键字和委托类名定义的引用类成员:
- public delegate void DoorHandler(String^ str);
-
- // Class with an event member
- public ref class Door
- {
- public:
- // An event that will call functions associated
- // with an DoorHandler delegate object
- event DoorHandler^ Knock;
-
- // Function to trigger events
- void TriggerEvents()
- {
- Knock("Fred");
- Knock("Jane");
- }
- };
Door类有一个名为Knock的事件成员,该事件对应于DoorHandler类型的委托。Knock是Door类的实例成员,但我们可以使用static关键字将某个事件指定为静态类成员,还可以将某个事件声明为virtual。当某个Knock事件被触发时,它可以调用具有DoorHandler委托指定的形参列表和返回类型的函数。