析构函数

在结构体一章中,我们学习了析构函数(参见 构造函数和析构函数章节)。我们简单回顾一下:析构函数是对象被销毁时调用的方法。析构函数与类的名称相同,但前缀是一个波浪号 (~)。析构函数不返回值,也没有任何参数。一个类只能有一个析构函数。

即使类没有析构函数或析构函数为空,编译器也会隐式地对以下类型的字段进行“垃圾回收”:字符串、动态数组和自动对象。

通常,析构函数会放在类的公共部分,但在某些特殊情况下,开发者可以将其移到一组 privateprotected 成员中。私有或受保护的析构函数不允许在代码中声明该类的自动变量。不过,我们稍后会了解 动态对象的创建 ,对它们来说,这样的限制还是有意义的。

特别是,有些对象的实现方式是,当不再需要它们时,它们必须删除自己(用于确定需求的概念可能不同)。也就是说,只要程序的任何部分还在使用对象,这些对象就会一直存在;一旦任务完成,这些对象就会自动销毁(私有析构函数保留了从类方法中删除对象的可能性)。

对于有经验的 C++ 程序员来说,请务必要注意,MQL5 中的析构函数总是虚拟的(更多关于虚方法的内容将在 虚方法(virtual 和 override)一节中介绍)。这一因素不会影响说明的语法。

在绘图程序示例中,从技术上讲,析构函数对于形状来说可能不是必需的。不过,为了追踪构造函数和析构函数的调用顺序,我们还是要加入一个。我们从输出方法全名的简化大纲开始:

class Shape
{
   ...
   ~Shape()
   {
      Print(__FUNCSIG__);
   }
};

我们很快就会在这个方法和其他方法中添加新内容,以便区分对象的不同实例。

考虑以下示例。在两种不同的上下文中描述一对对象 Shape:全局(在函数外部)和局部(在 OnStart 内部)。全局对象构造函数将在加载脚本后、调用 OnStart 前调用,而析构函数将在卸载脚本前调用。局部对象的构造函数将在包含变量定义的行中调用,而析构函数将在包含变量定义的代码块退出时调用,在本例中就是 OnStart 函数。

// the global constructor and destructor are related to script loading and unloading
Shape global;
 
// object reference does not create a copy and does not affect lifetime
void ProcessShape(Shape &shape)
{
   // ...
}
 
void OnStart()
{
   // ...
   Shape local// <- local constructor call
   // ...
   ProcessShape(local);
   // ...
// <- local destructor call

按引用将对象传递给其他函数不会创建对象的副本,也不会调用构造函数和析构函数。