27 Деструкторы: запуск, виртуальные
деструкторы, exit и деструкторы.
Деструктор класса вызывается для освобождения элементов объекта до разрушения самого объекта. Деструктор представляет метод с именем, совпадающим с именем класса, перед которым стоит символ тильда (~ ). Деструктор не может принимать параметров, а также не имеет объявленных типа возврата и значений.
class Х
{
public:
~Х();
//деструктор класса Х
};
Если деструктор не объявлен для класса явно, компилятор генерирует его автоматически.
Запуск деструкторов.
Вызов деструктора выполняется неявно, когда переменная выходит из своей объявленной области действия. Для локальных переменных деструкторы вызываются, когда перестает быть активным блок, в котором они объявлены. В случае глобальных переменных деструкторы вызываются как часть процедуры выхода после main.
Когда указатели объектов выходят за пределы области действия, неявный вызов деструктора не происходит. Это значит, что для разрушения такого объекта операция delete должна быть задана явно. Деструкторы вызываются строго в обратной последовательности вызова соответствующих конструкторов.
ехit и деструкторы
При вызове abort из программы деструкторы не вызываются, даже для переменных глобальной области действия.
Деструктор может быть также вызван явно одним из двух следующих
способов: косвенно, через вызов delete, или прямо, заданием полностью
уточненного имени деструктора, delete можно использовать
для разрушения объектов, для которых память распределялась при помощи new. Явный вызов деструктора необходим только в случае объектов, которым распределялся конкретный адрес памяти при помощи new.
class X {
…
~X();
…
};
void*
operator new(size_t size, void *ptr)
{
return ptr;
}
char
butter[sizeof(x)];
main()
{
X* pointer=new X;
X* exact_pointer;
exact_pointer=new(&buffer) X; //указатель инициализируется адресом буфера
…
delete pointer; //delete разрушает указатель
exact_pointer->X::~X(); //прямой вызов для отмены распределения памяти
}
Виртуальные
деструкторы.
Деструктор может быть объявлен как виртуальный. Это позволяет указателю объекта базового класса вызывать необходимый деструктор в случае, когда указатель фактически ссылается на объект производного класса. Деструктор класса, производного от класса с виртуальным деструктором, сам является виртуальным.
class color
{
public:
virtual ~со1ог(); //виртуальный деструктор для color
};
class red
: public color
{
public:
~red(); //деструктор для red также является виртуальным
};
class brightred :public red
{
public:
~brightred(); // деструктор для brightred также виртуальный
};
Ранее перечисленные классы и следующие объявления:
color *palette[3];
palette[0]=new
red;
palettei1]=new brightred;
palette[2]=new
color;
дадут такие результаты:
delele palette[0];
// Вызывается деструктор для red после которого
// вызывается деструктор для color
delete palette[1l;
//Первым вызывается деструктор для brightred, за ним
//~red и ~color
delete
palette[2];
//Запуск деструктора для color
Однако если ни один из деструкторов не был объявлен виртуальным, delete palette[0], delete palette[1] и delete palette[2] вызывают только деструктор для класса со1оr&. Это приведет к неправильному разрушению первых двух элементов, которые фактически имели тип red и brightred.