科技行者

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

知识库

知识库 安全导航

至顶网软件频道基础软件实例解析C++/CLI之静态构造函数

实例解析C++/CLI之静态构造函数

  • 扫一扫
    分享文章到微信

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

就某些类而言,当在程序中第一次使用时,最好能有一个初始化过程;当程序不再需要时,也最好能做一些收尾工作,这些都是非常好的类设计习惯。

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

关键字:

  • 评论
  • 分享微博
  • 分享邮件
使用这个类

  C++/CLI在非本地类中,引入了静态构造函数的概念,它的类名声明为static,如上例标号6所示。尽管一个静态构造函数是在类第一次使用之前被调用,但"使用"意味着什么呢?一个引用类静态构造函数的执行,是由类中对某个静态数据成员的第一次引用触发的。

  根据C++/CLI标准:一个静态构造函数不应有一个ctor初始化过程(ctor-initializer),静态构造函数也不可以被继承,且不能被直接调用。如果一个类的初始化过程带有静态字段,那么这些字段会在静态构造函数执行之前,以声明的顺序被初始化。
为静态构造函数生成的元数据总会标记为private,而不管它们是否带有声明或暗指的访问指定符。(但编译器会发出警告:"Accessibility on class constructor was ignored")。在本文写作时,至于一个带有给定访问指定符的静态构造函数,是否应为private之外的问题,仍在讨论之中,因此,访问指定符总是会被忽略。

  而一个没有显式指明静态构造函数的引用类,它的行为,就会像是有一个空的静态构造函数体一样。

  在上例标号6a中,利用AppDomain类,为当前线程获取了应用程序域(Application domains)。而根据CLI标准库:应用程序域表现为System::AppDomain对象,提供了隔离性、卸载及托管代码执行时的安全边界检查。多个应用程序域可运行于单个进程中,但是,也不存在应用程序域与线程的一对一关系,可以同时有几个线程属于某一个应用程序域,且同时某一个既定的线程也不会限制在某个单独的应用程序域中,但无论何时,一个线程只能在一个应用程序域中执行。

  用于追踪在程序执行时下一个可用的ID的文本文件名为"PointID.txt",与可执行程序位于同一目录中,如标号6b所示。(Concat可同时用于一个Unicode宽字符串及普通窄字符串,其会在编译时自动转换为宽字符串。)在标号6d中打开此文件,并在标号6e中读取,输入的字符串在标号6f中转换为一个整数,接着,在标号6g中关闭此文件。而try/catch块用于可能抛出的I/O异常。

  只读属性BaseDirectory与CurrentDomain是Microsoft对标准CLI库的扩展。

  在I/O中使用的类型,如StreamReader与File,存在于System::IO命名空间中。

  标号6h注册了一个处理函数,用于在程序快要结束时调用。注意,对一个类来说,没有静态析构函数。

  Finally子句

  C++/CLI支持对try/catch的一个扩展,也就是finally子句,位于它块内的代码总会被执行,而不管对应的try块中是否产生了一个异常。这就是说,finally子句会在try块正常结束后执行,或者说,会在与try相联的catch块之后执行。

  在上例的标号6j中,finally子句只是简单地把appDom句柄设置为null值,因此,就不会再对AppDomain对象进行访问了。但这种做法有点多余,因为父类块退出时,总会执行到这一行,所以,在此只是作为一个对此功能的简要介绍。

  事件处理

  CLI支持事件的概念,简单来说,一个事件就是一个非本地类成员,它可使一个对象或类提供通知机制。标准CLI类System::AppDomain包含了几个这样的事件,但Microsoft的扩展版本甚至包含了更多的事件,比如说ProcessExit,其在例2的标号6h中被引用。

  当一个特定的事件发生时,与事件相联的函数会以它们之前相联的顺序被调用,从最简单的形式来说,一个事件只与一个函数发生联系,而这也只是通过简单的赋值完成的,也就是说,包装了函数的代理被赋值给事件成员。而从更一般的形式来说,一个事件在不同时间,通过 += 复合赋值操作符,可与任意多个函数相联。之所以在标号6h中使用这个操作符,是因为不知道事件是否已与事件处理程序相联,如果已经相联,又使用了简单的 = 赋值符,那么这些函数将不再与此事件相联系。

  每个事件都有一个类型,以ProcessExit来说,类型为System::EventHandler,其是一个用于包装分别接受两个参数System::Object^ 与System::EventArgs^ 函数的代理类型,且有一个void返回类型。而定义在标号7中的ProcessExitHandler函数,也正好具有同样的特征(参数类型)。同时,在标号6h中,把此函数注册为一个事件处理程序,以便在进程退出的事件发生时调用。当这个函数被调用时,它会覆写此前的文本文件,写入一个下次执行时可用的ID值,而传递进来的参数会被忽略。

  代理

  根据C++/CLI标准:代理定义为一个从System::Delegate继承而来的类,它可用于调用所有带有一组参数的代理实例的函数。(注意,与指向成员函数的指针不同,一个代理实例能被绑定至任意类的成员,只要函数类型与代理类型匹配就可,所以,代理非常适合于"匿名"调用。)

  而在本例中,用到了一个定义在CLI库中的代理类型,名为System::EventHandler。然而,使用关键字delegate,也能定义自己的代理类型。在标号6h中,就使用了gcnew创建了一个代理的实例。由于被包装的函数为static,而构造函数的调用也只给了一个参数,所以,指向成员函数ProcessExitHandler的指针,其类型也必须与代理相匹配。(要包装一个实例函数,必须提供实例自身的句柄作为第一个参数。)
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

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

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