Конспект заняття на тему:"Класи ООП. Деструктори класу".

Про матеріал
В даному матеріалі міститься ознайомлення з поняттям деструктора класу, його роботи в порівнянні з роботою конструктора класу та особливості використання.
Перегляд файлу

Первомайський ЦНТТУМ

Гурток «Сучасні технології програмування»

Керівник гуртка Семенова Олена Анатоліївна

Розробка заняття на тему:

Тема: «Класи ООП. Деструктори.»

Мета:  повторити зміст поняття конструктора класу, види конструкторів, ознайомитись з поняттям деструктора класу, виховувати вміння встановлювати взаємозвʼязок та аналогію між програмними та реальними обʼєктами, розвивати увагу, спостережливість та логічне мислення.

Обладнання: ПК, ПЗ середовище програмування DevC++.

Хід заняття

1. Організаційний момент та розминка.

1. Для розминки, вже традиційно :) : складаємо 12 слів, що вміщують не менше 6 символів із літерами : «ф, і, в, а, п, р, о, л, д, ж, к, е, н, г, т, ь, и, м, ш, у, с, б, з, ц».

2. І трошки нетрадиційного :). Записуємо 1 рядок складених слів за допомогою сліпого десятипальцевого методу набору через кому. А другим завданням буде написати речення: «Мені зрозумілий принцип ООП - поліморфізм» .

3. Перевіряємо правильність набору та ставимо усні оцінки своїй роботі. Пам“ятаємо, що ми чесні :).

2.  Основна частина. Повторення та перехід до розгляду нової теми.

 Продовження вивчення класів та їх властивостей, а особливо, знайомство з новим поняттям «деструктори» нас, безумовно, вже зачекалось, але давайте все ж таки спочатку дещо повторимо. Як каже відоме прислів“я: “Повторення - Мати навчання”. :)

1. Що собою являє конструктор класу?

2. Які види конструкторів ви можете назвати?

3. Як ви розумієте «перевантаження» конструкторів? Як воно працює?

 Таким чином, ми пригадали, що конструктори — це особливий метод класу. Їх може бути декілька — за необхідністю. Перевантаження конструкторів дуже схоже на перевантаження функцій (тому що?- вони самі є функціями по суті) … Вони повинні мати одне й те саме ім“я, що є одночасно назвою класу то обов“язково повинні відрізнятись параметрами.

 Наприклад: один з конструкторів не приймає параметри (як він називається?), інший приймає два параметра, третій  - три (яка назва таких конструкторів?)… Під час створення об“єкта класу ці параметри передаються як значення полів. Тоді компілятор може визначити, який саме з заявлених у класі конструкторів треба застосувати при створенні об“єкту.

 Доречі, про параметри… Давайте поглянемо, як ви впорались із додаванням до програми, що ми складали на минулому занятті, конструктор, що повинен був ініціалізувати об“єкт класу з параметрами name та color (ім“я та колір).              

 Це, на перший погляд, нескладне завдання при реалізації його в програмі повинно було виявити парочку маленьких «граблів» :). Знайшли їх? :)

 В даному випадку було два основні варіанти: створити конструктор з двома або  з трьома параметрами. І виходячи з цього, два варіанти коректного виводу інформації про властивості об“єктів в консоль.

 На прикладі цієї задачі ми побачили, що конструктори застосовуються, щоб якимось чином створити клас, ініціалізувати поля класу, можливо, виконати якусь логіку — тобто, якийсь ланцюжок чи то послідовність дій при цьому.

 А так як у світі все повинно бути гармонійно :), то сьогодні ми розглянемо противагу конструкторам — деструктори.

 Тобто, якщо конструктор спрацьовує при  створенні  об“єкта класу, то деструктор починає працювати навпаки, при руйнуванні об“єкта класу. Напряму ми його як функцію викликати не можемо, тому що так само, як і конструктор, який працює тільки при створенні об“єкта класу, деструктор навпаки, спрацьовує тільки коли руйнується об“єкт класу. Скажімо, в тих випадках, коли об“єкт виходить із області видимості. Пам“ятаєте, що це таке?

 Для швидшого пригадування і як найпростіший приклад візьмемо функцію main. Де починається і закінчується її область видимості?

іnt main ()

{

Cats cat1;

cat1.Print();

return 0;

} 

 Ми створили в межах цієї функції об“єкт класу. І в той час, коли всі дії з ним закінчились, за межею ключового слова return відбувається вихід нашого об“єкту з області видимості функції. В цей момент все, що знаходиться в межах дії функції, знищується і, відповідно, звільняються ресурси, які були задіяні. Саме в цей момент викликається деструктор і, якщо в межах функції main було створено об“єкт класу, деструктор проводить дії, такі, що в ньому були описані. Це в тому випадку, коли такі дії взагалі були описані. Деструктор класу, аналогічно, як і конструктор, є в кожному класі, тому що створюється компілятором «за замовчуванням».

 Але якщо конструкторів можна створити безліч, то деструктор в класі може бути тільки один, або, як було вже сказано, не вказаний взагалі. В такому випадку, як і в випадку з конструктором, компілятор самостійно створить його «за замовчуванням». Якщо ж ми вирішили використати та написати деструктор, то він може знадобитись лише для того, щоб правильно звільнити ресурси, що були нами задіяні в класі.

 Розглянемо на простому прикладі. Створимо наш звичний, самий простенький клас котів, з паблік-полями «ім“я» та «вік».

 class  Cats //Об“являємо та описуємо клас котів з паблік-полями та методами

{public:

string name;

int age;

 

Cats() // Створюємо конструктор тільки для того, щоб побачити логи в консолі.

{ cout<<“ “<<endl;}

~Cats ()// Синтаксис деструктора абсолютно аналогічний синтаксису конструктора, за єдиним винятком: «тільда  ~ » перед назвою.

{ cout<<“Start destructor“<<endl;}

void Print ()

{ cout<<“cat name is -  \t“<<name<<“\tcat age is - \t“<<age<<endl;}

};

 

іnt main ()

{

Cats cat1;

cat1.Print();

return 0;} 

 Тепер після компіляції ми побачимо в консолі три рядка:

Start constructor

cat name is -    cat age is  - 406813570

Start destructor

 

Start constructor  -  є результатом звернення до конструктору в момент створення об“єкта класу.

cat name is -    cat age is  - 406813570   - є результатом роботи метода класу.

Start destructor  - це, після закінчення всіх дій функції , на виході з області видимості, викликається деструктор.

 

 Є деякі нюанси його роботи. Пропоную створити ще один об“єкт нашого класу і викликати для нього метод, щоб показати логи послідовності цих дій в консолі. Що ми побачимо?

 

class  Cats //Об“являємо та описуємо клас котів з паблік-полями та методами

{public:

string name;

int age;

 

Cats()

{ cout<<“ Start constructor“<<endl;}

~Cats ()

{ cout<<“Start destructor“<<endl;}

void Print ()

{ cout<<“cat name is -  \t“<<name<<“\tcat age is - \t“<<age<<endl;}

};

 

іnt main ()

{

Cats cat1;

cat1.Print();

Cats cat2;

cat2.Print();

return 0;} 

 Ми побачимо, що наш деструктор стартовал двічі. Чому? Тому що він відпрацював послідовно спочатку для одного, потім для другого об“єкта. Давайте перевіримо, в якій саме послідовності. Як це зробити?

 В наших об“єктів ініціалізуються два поля і обидва «сміттям». Але сміттям з унікальним значенням віку для кожного об“єкта.

 Якщо ми в cout<<“Start destructor“<<endl; внесемо зміну cout<<“Start destructor“<<“\tFor object\t“<<age<<endl;

 В принципі, таку саму зміну можна зробити і для конструктора. Тоді ми побачимо повну картину :).

 І яку ж саме картину ми побачимо в консолі?

Start constructor For object 406813570

cat name is -    cat age is  - 406813570

Start constructor For object  205067095

cat name is -    cat age is  - 205067095

Start destructor For object  205067095

Start destructor For object  406813570

 Тобто, деструктори викликаються в протилежному напрямку, ніж конструктори: спочатку для другого об“єкта, потім для першого.

 Можна також конкретніше визначитись з областю видимості для об“єкта нашого класу за допомогою простої функції.

 

F() //Пишемо функцію, яка буде створювати об“єкт класу.

{cout<<“Start F\t“<<endl;//Визначення початку роботи функції — Точка входу в область видимості

Cats cat3; //Створюємо об“єкт класу

cout<<“End F\t“<<endl;}/Визначення закінчення роботи функції — Точка виходу з області видимості

 

class  Cats //Об“являємо та описуємо клас котів з паблік-полями та методами

{public:

string name;

int age;

 

Cats()

{ cout<<“ Start constructor“<<endl;}

~Cats ()

{ cout<<“Start destructor“<<endl;}

void Print ()

{ cout<<“cat name is -  \t“<<name<<“\tcat age is - \t“<<age<<endl;}

};

 

F()

{cout<<“Start F\t“<<endl;

Cats cat3;

cout<<“End F\t“<<endl;}

іnt main ()

{

F();// Викликаємо функцію

cout<<“The end“<<endl;

return 0;} 

 Компіляція дасть нам такий результат:

Start F

Start constructor

End F

Start destructor

 

The end

 Якщо б ми зробимо уточнення за параметром, як в попередньому прикладі з віком, то побачимо, что викликаються і конструктор і деструктор для нашого створеного внутрі функції F об“єкта класу котів. Таким чином, область видимості нашого об“єкта в межах дії функції. За її межами об“єкт не видно.

 В даному конкретному випадку дії деструктора абсолютно марні, так як не мають ніякого особливого значення. Тому що в нашому об“єкті не треба звільняти ресурси.

 Але уявіть, що в нашому класі ми створили динамічний масив. Тоді нам потрібно було б виділяти динамічну пам“ять під цей масив. І якщо ви пам“ятаєте, в такому випадку нам треба подбати про те, щоб звільняти цю пам“ять.

 Але отримати доступ до пам“яті не вийде, оскільки поле, яке відповідає за масив, буде знаходитись в private секторі, тобто, інкапсульоване.

 Звільнити ресурси знадвору ми не зможемо, виходить, що пам“ять ніколи не звільниться і в результаті ми отримаємо витік пам“яті. Тому ми повинні подбати про те, щоб звільняти пам“ять всередині класу. Це можна зробити в деструкторі за допомогою уже відомого нам оператора delete, тоді пам“ять буде звільнятись в будь-якому випадку, оскільки деструктор про це подбає.

 Підведемо маленький підсумок: деструктор — це… спеціальний метод класу, що служить для деініціалізації об“єкта класу (наприклад, пам“яті) :).

 

 

docx
Додано
30 травня 2020
Переглядів
626
Оцінка розробки
Відгуки відсутні
Безкоштовний сертифікат
про публікацію авторської розробки
Щоб отримати, додайте розробку

Додати розробку