科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件实例解析C++/CLI之代理与事件

实例解析C++/CLI之代理与事件

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

在C++/CLI中,代理是对函数进行包装的对象;而事件是一种为客户程序提供通知的类机制。

作者:谢启东编译 来源:天极开发 2007年11月14日

关键字:

  • 评论
  • 分享微博
  • 分享邮件
 事件

  在C++/CLI中,事件是一种当某种重要事情发生时,为客户程序提供通知的机制。鼠标单击就是事件的一个典型例子,在事件发生之前,有关的客户程序必须先注册它们感兴趣的事件,如,当检测到鼠标单击时,这些程序就会接到通知。

  通过添加或删除一个或多个感兴趣的事件,事件列表可在运行时增长或缩减,请看例7中Server类型的定义,在标号1中,Server类定义了代理类型NewMsgEventHandler(一般约定在用于事件处理时,代理类型添加EventHandler的后缀名),接着,在标号2中,定义了一个名为ProcessNewMsg的公共事件(event在此为一个上下文关键字)。一个事件必须有一个代理类型,实际上,像这样的一个事件已经是一个代理实例了,而且因为它被默认初始化为nullptr,所以它没有调用列表。

  例7:

using namespace System;

public ref struct Server
{
 /*1*/ delegate void NewMsgEventHandler(String^ msg);
 /*2*/ static event NewMsgEventHandler^ ProcessNewMsg;
 /*3*/ static void Broadcast(String^ msg)
 {
  if (ProcessNewMsg != nullptr)
  {
   ProcessNewMsg(msg);
  }
 }
};

  当通过一条消息调用时,函数Broadcast将调用包装在ProcessNewMsg调用列表中所有的函数。

  Client类定义在例8中,一个Client的类型实例无论何时被创建,它都会通过向为Server::ProcessNewMsg维护的代理列表中添加一个实例函数(它关联到实例变量),来注册它所感兴趣的新Server消息,而这是通过 += 操作符来完成,如标号5中所示。只要这个入口一直保持在通知列表中,无论何时一个新消息送达Server,注册的函数都会被调用。

  例8:

using namespace System;
public ref class Client
{
 String^ clientName;
 /*4*/ void ProcessNewMsg(String^ msg)
 {
  Console::WriteLine("Client {0} received message {1}", clientName, msg);
 }
 public:
  Client(String^ clientName)
  {
   this->clientName = clientName;
   /*5*/ Server::ProcessNewMsg += gcnew Server::NewMsgEventHandler(this, &Client::ProcessNewMsg);
  }
  /*6*/ ~Client()
  {
   Server::ProcessNewMsg -= gcnew Server::NewMsgEventHandler(this, &Client::ProcessNewMsg);
  }
};

  要从通知列表中移除一个入口,可使用 -= 操作符,如标号6定义的析构函数中那样。

  例9:

using namespace System;

int main()
{
 Server::Broadcast("Message 1");
 Client^ c1 = gcnew Client("A");
 Server::Broadcast("Message 2");

 Client^ c2 = gcnew Client("B");
 Server::Broadcast("Message 3");

 Client^ c3 = gcnew Client("C");
 Server::Broadcast("Message 4");

 c1->~Client();
 Server::Broadcast("Message 5");

 c2->~Client();
 Server::Broadcast("Message 6");

 c3->~Client();
 Server::Broadcast("Message 7");
}

  例9是主程序,一开始,没有注册任何函数,所以当发送第一个消息时,不会获得任何通知。然而,一旦构造了c1,通知列表就包含了此对象的一个入口,而接下来c2与c3的构造使这个列表增长到3个入口。在这些对象消失时(通过显式调用析构函数),入口数也相应地减少了,直到最后,一个也不剩,因此当最后一条消息发出时,没有任何对象在监听。以下是输出:

Client A received message Message 2
Client A received message Message 3
Client B received message Message 3
Client A received message Message 4
Client B received message Message 4
Client C received message Message 4
Client B received message Message 5
Client C received message Message 5
Client C received message Message 6

  尽管3个对象均为同一类型,但这并不是必须的,只要定义的函数可与NewMsgEventHandler兼容,就能使用任意的类型。

  上述例子中使用的事件只不过是微不足道的一个示例,另外要说明一点,与以前文章中说过的属性一样,此种类型的事件均以private属性自动备份,且自动生成添加(add)与移除(remove)存取程序,为自定义这些存取程序,就必须提供这些函数的定义,如例10中所示,名称add与remove在此为上下文关键字。

  例10:

public ref struct Server
{
 // ...
 static event NewMsgEventHandler^ ProcessNewMsg {
  void add(NewMsgEventHandler^ n) { /* ... */ }
  void remove(NewMsgEventHandler^ n) { /* ... */ }
 }
 // ...
};

查看本文来源

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章