← Повернутися до лекцій

Лекція 14: Конструктори та Деструктори

Уявіть, що ви купуєте новий смартфон. Ви дістаєте його з коробки, і він вже має заряд батареї, встановлену мову і базові налаштування. Вам не треба збирати його з мікросхем. У програмуванні цю роль виконує конструктор.

1. Що таке Конструктор?

Конструктор — це спеціальний метод класу, який викликається автоматично в момент створення об'єкта. Його головна мета — ініціалізація (надати змінним початкові значення).

Правила конструктора:

  1. Має таку ж назву, як і клас.
  2. Не має типу повернення (навіть void писати не можна).
  3. Має бути 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. Деструктор (Прибиральник)

Коли об'єкт стає непотрібним (наприклад, функція завершилася і локальні змінні знищуються), викликається деструктор.

Правила деструктора:

  1. Назва класу зі знаком тильда ~ на початку (наприклад, ~Car).
  2. Не приймає параметрів.
  3. Існує тільки один на весь клас.
  4. Викликається автоматично.

Навіщо він треба?

Щоб звільнити пам'ять! Якщо ви виділяли пам'ять через 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. Життєвий цикл об'єкта

  1. Створення: Виділяється пам'ять → Викликається Конструктор.
  2. Життя: Ми користуємося методами об'єкта.
  3. Смерть: Вихід з області видимості (закрита дужка }) → Викликається Деструктор → Пам'ять звільняється.

Практичні завдання до Лекції 14

Виконайте ці завдання в своєму середовищі розробки.

Завдання 1: Персонаж гри

Створіть клас Character.

  1. Поля: name (string), hp (int).
  2. Створіть два конструктори:
    • Конструктор за замовчуванням: ім'я "Bot", здоров'я 100.
    • Параметризований: приймає ім'я та рівень здоров'я.
  3. У main створіть двох персонажів (одного без параметрів, іншого з параметрами) і виведіть їх дані на екран.

Завдання 2: Таймер (Імітація)

Створіть клас Timer.

  1. Поле: seconds.
  2. Конструктор: приймає кількість секунд і пише на екран "Таймер на [Х] сек запущено".
  3. Деструктор: пише на екран "Таймер зупинено. Час вийшов!".
  4. У main створіть об'єкт таймера всередині фігурних дужок (блок коду), щоб побачити, як спрацює деструктор при виході з блоку.
int main() {
    cout << "Start" << endl;
    {
        Timer t(10);
    } // Тут має спрацювати деструктор
    cout << "End" << endl;
    return 0;
}

Завдання 3: Безпечний масив (Рівень "Pro")

Це завдання поєднує класи і динамічну пам'ять. Створіть клас SafeArray.

  1. У конструкторі: приймайте розмір масиву, виділяйте під нього динамічну пам'ять (new int[size]) і заповнюйте нулями.
  2. У деструкторі: звільняйте цю пам'ять (delete[]).
  3. Створіть методи: set(index, value) і get(index).
  4. Важливо: У цих методах додайте перевірку: якщо індекс виходить за межі масиву — виводьте помилку і не робіть дію. Це захистить програму від краху.