引用类的析构函数和终结器

来源:互联网 发布:汤圆的一个软件 编辑:程序博客网 时间:2024/05/16 19:17

摘要:《Visual C++ 2008入门经典》第9章类继承和虚函数,本章我们将研究面向对象编程的核心主题-- 类继承。本小节为大家介绍引用类的析构函数和终结器。

 

      我们可以用为本地C++类定义析构函数时所用的相同方式,为引用类定义析构函数。当某个引用类的句柄离开其作用域时,或者当该类的对象是另一个正在被销毁的对象的组成部分时,类的析构函数将被调用。我们也可以对引用类的句柄应用delete运算符,这样也会调用析构函数。为本地C++类实现析构函数的首要原因是要处理在堆上分配的数据成员,但该理由显然不适用于引用类,因此在引用类中很少需要定义析构函数。当类对象要使用不被垃圾回收器管理的其他资源时,我们可能才需要定义析构函数。我们也可以使用另一种名为终结器(finalizer)的类成员来清除这样的资源。

      终结器是一种特殊的引用类函数成员,是在销毁对象的时候由垃圾回收器自动调用的。注意,如果析构函数被显式调用,或者因为对某个对象应用delete运算符而被调用,那么垃圾回收器将不会为该对象调用终结器。在派生类中,调用终结器的顺序与调用析构函数的顺序相同,因此最基本的类的终结器被首先调用,然后是类层次结构中下一个类的终结器被调用,最后被调用的是最后派生的那个类的终结器。

 

     

下面是定义类终结器的方法:

  1. public ref class MyClass  
  2. {  
  3. // Finalizer definition  
  4. !MyClass()  
  5. {  
  6. // Code to clean-up when an object is destroyed...  
  7. }  
  8. // Rest of the class definition...  
  9. }; 

      在类中定义终结器的方法与定义析构函数的类似,但需要用!代替为析构函数使用的类名前面的~符号。与析构函数一样,我们决不能为终结器提供返回类型,而终结器的访问说明符也将被忽略。通过下面这个小示例,我们可以了解一下析构函数和终结器的工作情况。

 

     

试一试:终结器和析构函数

该示例说明了应用程序中调用析构函数和终结器的时间:

  1. // Ex9_20.cpp : main project file.  
  2. // Finalizers and destructors  
  3.  
  4. #include "stdafx.h"  
  5.  
  6. using namespace System;  
  7.  
  8. ref class MyClass  
  9. {  
  10. public:  
  11. // Constructor  
  12. MyClass(int n) : value(n){}  
  13.  
  14. // Destructor  
  15. ~MyClass()  
  16. {  
  17. Console::WriteLine("MyClass object({0}) destructor called.", value);  
  18. }  
  19.  
  20. // Finalizer  
  21. !MyClass()  
  22. {  
  23. Console::WriteLine("MyClass object({0}) finalizer called.", value);  
  24. }  
  25. private:  
  26. int value;  
  27. };  
  28.  
  29. int main(array<System::String ^> ^args)  
  30. {  
  31. MyClass^ obj1 = gcnew MyClass(1);  
  32. MyClass^ obj2 = gcnew MyClass(2);  
  33. MyClass^ obj3 = gcnew MyClass(3);  
  34. delete obj1;  
  35. obj2->~MyClass();  
  36.  
  37. Console::WriteLine(L"End Program");  
  38. return 0;  

该示例的输出如下:

  1. MyClass object(1) destructor called.  
  2. MyClass object(2) destructor called.  
  3. End Program  
  4. MyClass object(3) finalizer called. 

示例说明

      MyClass类包含一个构造函数、一个析构函数和一个终结器。析构函数和终结器仅仅将输出写到命令行上,以便使我们知道它们被调用的时间。我们还能够辨别出是哪个对象调用了终结器或析构函数,因为这两个函数还将输出value字段的值。

      在main()函数中,我们创建了3个为了区别而封装了数值1、2和3的MyClass类型的对象。然后,我们先是对obj1应用delete运算符,之后又显式调用obj2的析构函数。这些显式动作导致的对对象析构函数的调用生成了前两行输出。

      下一行输出是main()中return语句之前的那条语句产生的,因此obj3的终结器生成的最后一行输出发生在main()结束之后。输出表明,当我们删除某个对象或显式调用某个对象的析构函数时,该对象的析构函数将被执行,这些操作同时禁止了该对象的终结器的执行。obj3引用的对象是程序终止时由垃圾回收器销毁的,因此调用了终结器来清除任何不受管理的资源。

      因此,如果某个类既有终结器,又有析构函数,则销毁对象时只能调用其中之一。如果我们以编程方式销毁对象,则析构函数被调用;如果对象因离开作用域而自然消亡,则终结器被调用。由此还可以得出下面的结论:如果我们依赖终结器来完成销毁对象之后的清理工作,则不应该显式删除对象。

      如果我们使main()中销毁obj1和obj2的语句以注释形式存在,那么将看到程序结束时垃圾回收器调用了所有这3个对象的终结器。另一方面,如果我们使MyClass类的终结器以注释形式存在,那么将发现垃圾回收器没有调用obj3的析构函数,因此没有任何清理动作发生。我们的结论如下:如果无论对象以怎样的方式终止,都希望确保对象使用的不受管理的资源能够得到清理,则应该在类中既实现析构函数,又实现终结器。

 

回书目   上一节   下一节

 

上一篇: 9.9.7 委托和事件(5) 下一篇: 9.9.9 通用类(1)
原创粉丝点击