2.6. Деструктор

Деструктором называется составная функция класса, которая вызывается перед разрушением объекта. Это означает, что деструктор вызывается в следующих случаях:

· при выходе из области видимости;

· при выполнении операции delete для объектов, размещенных в динамической памяти;

· непосредственно, как составная функция.

Уже обсуждалось, что класс может иметь несколько конструкторов, все эти конструкторы имеют одинаковое имя, совпадающее с именем класса. Приведём правила определения деструкторов:

· класс имеет ровно один деструктор;

· имя деструктора совпадает с именем класса с добавленным впереди символом тильды «~»;

· деструктор не имеет аргументов и не имеет возвращаемого значения.

Если же деструктор не определить явно, то он будет определен по умолчанию, как составная функция

~ имя_класса() {};

и будет находиться в открытой части класса.

Пример. Определим класс, объектом которого является стек, состоящий из элементов, размещающихся в массиве целых чисел. Поскольку конструктор будет захватывать динамическую память, то необходим деструктор, который эту память будет освобождать после окончания работы со стеком.

#include <iostream.h>

#include <conio.h>

// Класс — целочисленный стек

class IntStack

      {

      // Закрытые элементы

            int *v;                 // Массив под стек

            int size, top;    // Размер стека и положение вершины

      public:     // Общедоступные элементы

            IntStack(int n = 10): size(n), top(n)    // Конструктор

                  {

                  v = new int[n];   // Выделение памяти под массив (стек)

                  }

            ~IntStack() // Деструктор

                  {

                  delete []v; // Освобождение памяти

                  }

            int& operator++(int);   // Перегрузка постфиксной операции ++

            int operator—();       // Перегрузка префиксной операции —

      };

int& IntStack::operator++(int)     // Перегрузка постфиксной операции ++

      {

      return v[—top];

      }

int IntStack::operator—()   // Перегрузка префиксной операции —

      {

      return v[top++];

      }

int main()

      {

      clrscr();   // Очистка экрана

      IntStack *ps = new IntStack(20);   // Создание стека ps

                                         // в динамической памяти

      IntStack s; // Создание стека s (по умолчанию 10 элементов)

      for(int i = 0; i < 10; i++)

            s++ = i;         // запись чисел 0,1,2,… в стек

      cout<<"Содержимое стека:n";

      for(int j = 0; j < 10; j++)

            cout << —s << ‘n';          // Чтение из стека

      (*ps)++ = 100;    // Пример занесения в стек ps числа 100

      s.~IntStack(); // Явное разрушение стека s

      delete ps;     // Разрушение стека ps

      getch();    // Ожидание нажатия клавиши

      return 0;   // Выход из программы

      }

В результате работы этой программы на экран будут выведены числа 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 , каждое с новой строки.

Пример. Определим класс трассировочного типа, позволяющий отслеживать вход в блок и выход из блока программы, для которого определен объект этого класса. Воспользуемся с этой целью свойством запуска конструктора при вхождении в блок, содержащий объект, инициализируемый этим конструктором. При выходе из блока будет вызываться деструктор.

      #include <stdio.h>

      #include <conio.h>

      #include <iostream.h>

     

      // Трассировочный класс

      class trace

            {

                  const char* msg;

            public:

                  trace(char *m): msg(m)  // Конструктор

                        {

                        // Вывод сообщения о входе в блок

                        fprintf(stderr, "Входим в %sn", msg);

                        }

     

                  ~trace()    // Деструктор

                        {

                        // Вывод сообщения о выходе из блока

                        fprintf(stderr, "Выходим из %sn", msg);

                        }

            };

      void subr()

            {

            trace t("subr");

            }

      int main()

            {

            clrscr();   // Очистка экрана

            trace t("main");

            cout<<‘n';                        // Перевод строки

            subr();

              cout<<‘n';                                                      // Перевод строки

            for(int i = 0; i < 5; i++)

                  {

                  trace t("internal");

                  }

            cout<<‘n';                        // Перевод строки

     

            return 0;   // Выход из программы

            }

Результаты работы программы

Входим в main

Входим в subr

Выходим из subr

Входим в internal

Выходим из internal

Входим в internal

Выходим из internal

Входим в internal

Выходим из internal

Входим в internal

Выходим из internal

Входим в internal

Выходим из internal

Выходим из main