- •1. Краткие теоретические сведения
- •1.1. Объектно-ориентированный подход-Бузюков
- •1.2. Этапы разработки ооп систем
- •1.3. Декомпозиция
- •1.5. Концепции ооп
- •1.6. Синтаксис объявления класса
- •1.7. Методы класса
- •1.8. Объявление объектов
- •1.9. Конструктор
- •1.10. Деструктор
- •1.11. Инкапсуляция
- •1.12. Полиморфизм
- •1.13. Указатель this
- •1.14. Статические члены класса
- •1.15. Дружественные функции и классы
- •1.16. Вложенные классы
- •1.17. Элементы класса
- •1.17.1. Данные-элементы
- •1.17.2. Элементы-функции
- •1.17.3. Доступ к данным-элементам
- •1.17.4. Вызов функций-элементов
- •1.17.5. Указатели на компоненты-функции.
- •2. Задание
- •2.4.1.2. Пример для варианта 30
- •2.4.1.2.1. Разработка алгоритма решения.
- •2.4.1.2.2. Описание структуры класса.
- •2.4.1.2.2.1. Описание полей класса.
- •2.4.1.2.2.2. Функции-аксессоры.
- •2.4.1.3. Программа
- •2.4.1.4. Тестирование
- •2.4.2. Задание 2. Простейшие классы и объекты
- •2.4.2.1. Условие задания
- •2.4.2.2. Пример
- •2.4.2.3. Программа
- •2.4.2.4. Тестирование
- •2.4.3. Задание 3. Простейший класс. Объединение данных и методов
- •2.4.3.1. Условие задания
- •2.4.3.2. Пример
- •2.4.3.3. Программы
- •2.4.3.3.1. Первый принцип инкапсуляции: объединение данных и методов
- •2.4.3.3.2. Второй принцип инкапсуляции: защита от внешнего вмешательства
- •2.4.3.3.3. Независимость интерфейса от реализации
- •2.4.3.3.4. Конструктор, деструктор
- •2.4.3.3.5. Определение методов вне класса
- •2.4.3.3.6. Конcтантные поля, методы и объекты
- •2.4.3.4. Тестирование
- •2.4.4. Задание 4. Пользовательский класс
- •2.4.4.1. Условие задания
- •2.4.4.2. Методические указания.
- •1. Пример определения класса.
- •2. Пример реализации конструктора с выдачей сообщения.
- •3. Выводы
- •4. Требование к отчету
- •4. Краткие теоретические сведения.
- •5. Вопросы для самоконтроля
- •Литература
- •1. Краткие теоретические сведения 2
- •1.1. Объектно-ориентированный подход-Бузюков 2
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