Объектно-ориентированное программирование - Учебное пособие (А.А. Хусаинов)

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<<"Содержимое стека: ";

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

               cout << --s << ' ';          // Чтение из стека

 

   (*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, "Входим в \%s ", msg);

                                       }

  

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

                                       {

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

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

                                       }

               };

 

   void subr()

               {

               trace t("subr");

               }

 

   int main()

               {

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

 

               trace t("main");

 

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

               subr();

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

 

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

                           {

                           trace t("internal");

                           }

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

  

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

               }

 

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

 

Входим в main

 

Входим в subr

Выходим из subr

 

Входим в internal

Выходим из internal

Входим в internal

Выходим из internal

Входим в internal

Выходим из internal

Входим в internal

Выходим из internal

Входим в internal

Выходим из internal

 

Выходим из main