Лекція 14: Конструктори та Деструктори
Уявіть, що ви купуєте новий смартфон. Ви дістаєте його з коробки, і він вже має заряд батареї, встановлену мову і базові налаштування. Вам не треба збирати його з мікросхем. У програмуванні цю роль виконує конструктор.
1. Що таке Конструктор?
Конструктор — це спеціальний метод класу, який викликається автоматично в момент створення об'єкта. Його головна мета — ініціалізація (надати змінним початкові значення).
Правила конструктора:
- Має таку ж назву, як і клас.
- Не має типу повернення (навіть
voidписати не можна). - Має бути
public(у 99% випадків).
Синтаксис:
#include <iostream>
#include <string>
using namespace std;
class User {
public:
string name;
int age;
// Це конструктор
User() {
name = "Guest"; // Значення за замовчуванням
age = 18;
cout << "Створено нового користувача!" << endl;
}
};
int main() {
User u1; // Тут АВТОМАТИЧНО викликається конструктор
cout << u1.name; // Виведе "Guest"
return 0;
}
2. Параметризований конструктор (Перевантаження)
Щоб створювати об'єкти з конкретними даними, передаємо параметри в конструктор. Клас може мати кілька конструкторів (перевантаження), якщо списки параметрів різні.
#include <iostream>
#include <string>
using namespace std;
class Car {
public:
string model;
int speed;
// 1. Конструктор за замовчуванням (без параметрів)
Car() {
model = "Unknown";
speed = 0;
}
// 2. Конструктор з параметрами
Car(string m, int s) {
model = m;
speed = s;
}
};
int main() {
Car c1; // Викличеться 1-й (Unknown, 0)
Car c2("Tesla", 250); // Викличеться 2-й
return 0;
}
Важливо: Якщо ви написали тільки конструктор з параметрами, компілятор "відбере" у вас стандартний порожній конструктор. Тобто писати Car c1; стане заборонено, доки ви не додасте Car() {} вручну.
3. Список ініціалізації
Професійні C++ програмісти рідко присвоюють значення всередині фігурних дужок конструктора (наприклад, speed = s). Замість цього використовують список ініціалізації, який працює швидше.
Професійний стиль:
#include <iostream>
#include <string>
using namespace std;
class Car {
public:
string model;
int speed;
// Професійний стиль
Car(string m, int s) : model(m), speed(s) {
// Тіло конструктора залишається пустим або містить додаткову логіку
}
};
int main() {
Car c1("Tesla", 250);
return 0;
}
4. Деструктор (Прибиральник)
Коли об'єкт стає непотрібним (наприклад, функція завершилася і локальні змінні знищуються), викликається деструктор.
Правила деструктора:
- Назва класу зі знаком тильда
~на початку (наприклад,~Car). - Не приймає параметрів.
- Існує тільки один на весь клас.
- Викликається автоматично.
Навіщо він треба?
Щоб звільнити пам'ять! Якщо ви виділяли пам'ять через new у конструкторі, ви зобов'язані зробити delete у деструкторі.
#include <iostream>
using namespace std;
class ArrayHandler {
private:
int* arr; // Вказівник для динамічного масиву
int size;
public:
// Конструктор: Виділяємо пам'ять
ArrayHandler(int n) {
size = n;
arr = new int[size]; // ЗАЙМАЄМО ПАМ'ЯТЬ
cout << "Пам'ять виділено для " << size << " елементів." << endl;
}
// Деструктор: Звільняємо пам'ять
~ArrayHandler() {
delete[] arr; // ЧИСТИМО ПАМ'ЯТЬ
cout << "Пам'ять очищено. Об'єкт знищено." << endl;
}
};
int main() {
if (true) {
ArrayHandler list(5); // Конструктор викликався тут
} // Тут блок if закінчився -> викликається Деструктор
cout << "Кінець програми." << endl;
return 0;
}
Без деструктора пам'ять залишилася б зайнятою (витік пам'яті).
5. Життєвий цикл об'єкта
- Створення: Виділяється пам'ять → Викликається Конструктор.
- Життя: Ми користуємося методами об'єкта.
- Смерть: Вихід з області видимості (закрита дужка
}) → Викликається Деструктор → Пам'ять звільняється.
Практичні завдання до Лекції 14
Виконайте ці завдання в своєму середовищі розробки.
Завдання 1: Персонаж гри
Створіть клас Character.
- Поля:
name(string),hp(int). - Створіть два конструктори:
- Конструктор за замовчуванням: ім'я "Bot", здоров'я 100.
- Параметризований: приймає ім'я та рівень здоров'я.
- У
mainстворіть двох персонажів (одного без параметрів, іншого з параметрами) і виведіть їх дані на екран.
Завдання 2: Таймер (Імітація)
Створіть клас Timer.
- Поле:
seconds. - Конструктор: приймає кількість секунд і пише на екран "Таймер на [Х] сек запущено".
- Деструктор: пише на екран "Таймер зупинено. Час вийшов!".
- У
mainстворіть об'єкт таймера всередині фігурних дужок (блок коду), щоб побачити, як спрацює деструктор при виході з блоку.
int main() {
cout << "Start" << endl;
{
Timer t(10);
} // Тут має спрацювати деструктор
cout << "End" << endl;
return 0;
}
Завдання 3: Безпечний масив (Рівень "Pro")
Це завдання поєднує класи і динамічну пам'ять. Створіть клас SafeArray.
- У конструкторі: приймайте розмір масиву, виділяйте під нього динамічну пам'ять (
new int[size]) і заповнюйте нулями. - У деструкторі: звільняйте цю пам'ять (
delete[]). - Створіть методи:
set(index, value)іget(index). - Важливо: У цих методах додайте перевірку: якщо індекс виходить за межі масиву — виводьте помилку і не робіть дію. Це захистить програму від краху.