Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЛР20-С++-16-сентября-2012 (1).doc
Скачиваний:
33
Добавлен:
12.11.2019
Размер:
1.18 Mб
Скачать

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

Для разрушения объекта используется метод, называемый деструктором.

Деструктор выполняет функцию, обратную конструктору. При удалении объекта вызывается метод-деструктор, имя которого совпадает с именем класса, но вначале приписана тильда ~. В основном деструкторы применяют в том случае, когда выполнялось динамическое создание внутренних объектов или динамическое выделение памяти. Тогда внутри деструктора необходимо освободить зарезервированную память.

Деструктор класса – специальная функция класса, которая уничтожает объект, когда необходимость в нем отпадает или время его жизни завершено.

Имя деструктора совпадает с именем класса, которому предшествует знак

~(тильда).

Деструктор не принимает параметров и не возвращает значения. Таким образом, деструктор в классе всегда один.

Деструктор не имеет параметров и включается в раздел public. Так применительно к примеру 20.7 конструкция деструктора приведена в примере 20.13.

Пример 20.13.

class Printer

{

public:

Printer(char* _model, int _year); //Конструктор с параметрами

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

};

Компилятор предоставляет деструктор по умолчанию.

Деструктор может отсутствовать в составе класса, тогда для разрушения объекта создается деструктор по умолчанию.

Однако, если Вы захватывали какие-либо ресурсы при создании объекта (например, динамически выделяли память), Вы обязаны переопределить деструктор для корректного освобождения ресурсов.

Деструктор обязательно должен быть включен в класс, если какие-либо свойства класса помещаются в динамической памяти.

Пример 20.14.

Рассмотрим пример с классом Printer (пример 20.7), где одно из свойств (название модели) помещается в динамической памяти:

 

class Printer

{

char* model; //указатель на строку, которая будет

//содержать название модели и разместится

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

int year; //год выпуска

int status; //состояние принтера

public:

Printer(char* _model, int _year);

~Printer();

void set_print();

void stop_print();

void show();

};

Конструктор:

Printer :: Printer(char* _model, int _year)

{

int len=strlen(_model); //Определение длины

//строки

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

//для размещения строки и символа '\0'

model=new char[len+1];

strcpy(model, _model);

year=_year;

status=0;

}

 

Деструктор:

Printer :: ~Printer()

{

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

delete[] model;

//Присваивание указателю значения пустого

//указателя, обязательно в Visual C++

model = NULL;

}

Тогда программа, выполняющая все этапы работы с объектом, будет выглядеть так:

int main(void)

{

Printer printer("HP5P",2004); //Создание объекта

printer.show();

return 0;

}

Пример 20.15.

Создать программу решения примера 20.7 на основе конструктора с параметрами и с использованием деструктора.

Полный текст программы для примера 20.15:

//Пример 20.15

#include <iostream.h>

#include <conio.h>

class Printer

{

private:

char* model;//указатель на строку, которая будет

//содержать название модели принтера

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

int year; //год выпуска

int status; //состояние принтера

public:

//Конструктор с параметрами

Printer(char* _model, int _year);

//Деструктор

~Printer();

void init_printer(char* _model, int _year);

void set_print();

void stop_print();

void show();

};

void Printer::init_printer(char* _model,int _year)

{

strcpy(model,_model); //инициализация свойства model

year=_year; //инициализация свойства year

status=0; //начальное состояние - готов к печати

}

void Printer :: set_print()

{

if (!status) status=1;

}

void Printer :: stop_print()

{

status = 0;

}

void Printer :: show()

{

cout<<"Model: "<<model<<" year: "<<year<<" status: "<<status<<endl;

}

//Конструктор с параметрами

Printer :: Printer(char* _model, int _year)

{

int len=strlen(_model); //Определение длины

//строки

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

//для размещения строки и символа '\0'

model=new char[len+1];

strcpy(model, _model);

year=_year;

status=0;

}

//Деструктор

Printer :: ~Printer()

{

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

delete[] model;

//Присваивание указателю значения пустого

//указателя, обязательно в Visual C++

model = NULL;

}

int main()

{

//Создание первого объекта

Printer printer1("HP5P",2004);

printer1.show();

//Создание второго объекта

Printer printer2("Canon_BJC250",2000);

printer2.show();

cout << "\nНажмите любую клавишу..." ;

getch();

return 0;

}

При выполнении этой программы на экран будет выведено сообщение:

Model: HP5P year: 2004 status: 0

Model: Canon_BJC250 year: 2000 status: 0

Явный вызов деструктора не требуется, так как его вызов будет выполнен автоматически в точке программы, где объект должен быть разрушен в соответствии с его временем жизни.

Деструктор является дополнением конструктора. Он вызывается всякий раз, когда уничтожается представитель класса. Объект считается уничтоженным, когда завершил работу деструктор объекта.

Для деструктора существуют следующие правила:

  • деструктор не может иметь аргументов;

  • деструктор не может возвращать значения;

  • деструктор не наследуется (исключением является виртуальный деструктор);

  • для одного класса может существовать только один деструктор;

  • если деструктор не задан явным образом, то автоматически создаётся пустой деструктор.

Пример 20.16.

//file ctime.h

#ifndef __CTIME_H__

#define __CTIME_H__

class CTime

{ char *timestr;

public:

CTime(char *str=”00:00:00”); //конструктор по умолчанию

CTime(const CTime& clk); //копирующий конструктор

~CTime(); //деструктор

show(); //функция-элемент

}; //обязательно ставить точку с запятой, т.к. class –

// объявление типа

#endif

//file ctime.cpp

#include <string.h>

#include <iostream.h>

#include “ctime.h”

CTime:: CTime(char *str=”00:00:00”)

{ timestr=new char[strlen(str)+1];

strcpy(timestr,str);

}

CTime:: CTime(const time& clk)

{ timestr=new char[strlen(clk.timestr)+1];

strcpy(timestr,clk.timestr);

}

CTime::~ CTime()

{ delete [] timestr;

}

CTime::show()

{ cout<<”Time is “<<timestr<<endl;

}

//file main.cpp

#include “ctime.h”

void main(void)

{ CTime a; //для а вызывается конструктор по умолчанию

CTime *b=new CTime; //для b вызывается конструктор по

// умолчанию

CTime e(a); //для e вызывается копирующий конструктор

//вызовем функцию-элемент

a.show(); //00:00:00

b->show(); //00:00:00

e,show; //00:00:00

}

//в конце области видимости автоматически вызываются деструкторы объектов в порядке, обратном вызову конструкторов, т.е. сначала для е, затем для d и т.д..

Пример 20.17. Описать и определить класс-список.

Файл list.h содержит описание класса.

#ifndef __LIST_H__

#define __LIST_H__

struct list

{

int inf; // информационное поле

list *next; // указатель на следующий элемент списка

};

class CSpisok

{

list* head; // указатель на начало списка

public:

CSpisok (int);

CSpisok (CSpisok&);

void print ();

~CSpisok();

};

#endif

Файл list.cpp содержит определение функций-элементов.

#include <stdlib.h>

#include <iostream.h>

#include <iomanip.h>

#include "list.h"

CSpisok:: CSpisok(int n)

//конструктор инициализирует список из n элементов по принципу

// "очередь"

{ head = NULL;

list *p,*pn;

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

{

p = new list;

p>inf = random(100)-50;

p>next = NULL;

if (head == NULL) head = p;

else pn>next = p;

pn = p;

}

}

CSpisok:: CSpisok (const CSpisok& s)

//конструктор копии класса CSpisok

{ head = NULL;

list *sp = s.head, *p, *pn;

while (sp)

` { p = new list;

p>inf = sp>inf;

p>next = NULL;

if (head == NULL) head = p;

else pn>next = p;

pn = p;

sp = sp>next;

}

}

CSpisok::~ CSpisok()

//деструктор - уничтожает объект класса список из памяти

{ list *p;

while (head)

{ p = head;

head = head>next;

delete p;

}

}

void CSpisok::print()

//функция-элемент печати содержимого списка

{ list *p = head;

while (p)

{ cout<<setw(5)<<p>inf;

p = p>next;

}

cout<<endl;

}

Файл main.cpp содержит основную функцию.

#include <iostream.h>

#include <iomanip.h>

#include “list.h”

void main (void)

{ spisok s1(10), // создание списка из 10 элементов

s2(s1), // s2- копия списка s1

s3(15); // создание списка из 15 элементов

s1.print(); // печать s1

s2.print(); // печать s2

s3.print(); // печать s3

}

В проект включены файлы: main.cpp и list.cpp.

Результаты выполнения программы:

-49 -50 -17 -47 -15 -29 3 -31 20 44

-49 -50 -17 -47 -15 -29 3 -31 20 44

-23 -6 -40 19 6 -46 -34 31 18 26 32 45 -29 -8 45