Урок №124. Конструктори

  Юрій  | 

  Оновл. 2 Лют 2021  | 

 222

На цьому уроці ми розглянемо конструктори в мові С++.

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

Коли всі члени класу (або структури) є відкритими, то ми можемо ініціалізувати клас (або структуру) напряму, використовуючи список ініціалізаторів або uniform-ініціалізацію (в C++11):

Проте, як тільки ми зробимо будь-які змінні-члени класу закритими, то більше не зможемо ініціалізувати їх напряму. В цьому є сенс: якщо ви не можете напряму звертатися до змінної (бо вона закрита), то ви і не повинні мати можливість напряму її ініціалізувати.

Як тоді ініціалізувати клас з закритими змінними-членами? Використовувати конструктори.

Конструктор — це особливий тип методу класу, який автоматично викликається при створенні об’єкта цього ж класу. Конструктори зазвичай використовуються для ініціалізації змінних-членів класу значеннями, які надані за замовчуванням/користувачем, або для виконання будь-яких кроків налаштування, необхідних для використовуваного класу (наприклад, відкрити певний файл або базу даних).

На відміну від звичайних методів, конструктори мають певні правила щодо своїх імен:

   конструктори завжди повинні мати те ж ім’я, що і клас (враховуючи верхній і нижній регістри);

   конструктори не мають типу повернення (навіть void).

Зверніть увагу, конструктори призначені тільки для виконання ініціалізації. Не слід намагатися викликати конструктор для повторної ініціалізації існуючого об’єкта. Хоча це може скомпілюватися без помилок, результати можуть вийти несподівані (компілятор створить тимчасовий об’єкт, а потім видалить його).

Конструктори за замовчуванням

Конструктор, який не має параметрів (або містить параметри, всі з яких мають значення за замовчуванням), називається конструктором за замовчуванням. Він викликається, якщо користувачем не вказані значення для ініціалізації. Наприклад:

Цей клас містить дріб у вигляді окремих значень типу int. Конструктор за замовчуванням називається Fraction (як і клас). Оскільки ми створили об’єкт класу Fraction без аргументів, то конструктор за замовчуванням спрацював відразу ж після виділення пам’яті для об’єкта, і ініціалізував наш об’єкт.

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

0/1

Зверніть увагу, наш чисельник (m_numerator) і знаменник (m_denominator) були ініціалізовані значеннями, які ми вказали в конструкторі за замовчуванням! Це настільки корисна особливість, що майже кожен клас має свій конструктор за замовчуванням. Без нього значеннями нашого чисельника і знаменника було б сміття до тих пір, поки ми явно не присвоїли б їм нормальні значення.

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

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

Зверніть увагу, тепер у нас є два конструктори: конструктор за замовчуванням, який буде викликатися, якщо ми не надамо значення, і конструктор з параметрами, який буде викликатися, якщо ми надамо значення. Ці два конструктора можуть мирно співіснувати в одному класі завдяки перевантаженню функцій. Фактично, ви можете визначити будь-яку кількість конструкторів до тих пір, поки у них будуть унікальні параметри (враховується їх кількість і тип).

Як використовувати конструктор з параметрами? Все просто! Пряма ініціалізація:

Тут ми ініціалізували наш дріб числами 4 і 5, результат — 4/5!

У C++11 ми також можемо використати uniform-ініціалізацію:

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

Значення за замовчуванням для конструкторів працюють точно так же, як і для будь-якої іншої функції, тому у вищенаведеному прикладі, коли ми викликаємо seven(7), викликається Fraction(int, int), другий параметр якого дорівнює 1 (значення за замовчуванням).

Правило: Використовуйте пряму ініціалізацію або uniform-ініціалізацію з об’єктами ваших класів.

Копіююча ініціалізація

Подібно звичайним змінним, класи також можна ініціалізувати, використовуючи копіюючу ініціалізацію:

Однак рекомендується уникати цієї форми ініціалізації класів, так як вона може бути менш ефективною. Хоча uniform-ініціалізація, пряма і копіююча ініціалізації працюють однаково з фундаментальними типами даних, з класами це не зовсім так (хоча кінцевий результат часто збігається). Ми розглянемо цей момент більш детально на наступних уроках.

Правило: Не використовуйте копіюючу ініціалізацію з об’єктами ваших класів.

Зменшення кількості конструкторів

У прикладі з класом Fraction і двома конструкторами (за замовчуванням і з параметрами), конструктор за замовчуванням насправді зайвий. Ми могли б спростити цей клас наступним чином:

Хоча цей конструктор як і раніше є конструктором за замовчуванням, він тепер визначений таким чином, що може приймати одне або два значення, надані користувачем:

На практиці намагайтеся зменшувати кількість конструкторів вашого класу.

Конструктор за замовчуванням, що неявно генерується

Якщо ваш клас не має конструкторів, то мова C++ автоматично згенерує для вашого класу відкритий конструктор за замовчуванням. Його іноді називають неявним конструктором (або “конструктором, що неявно генерується”). Розглянемо наступний клас:

У цього класу немає конструктора, тому компілятор згенерує наступний конструктор:

Цей конструктор дозволяє створювати об’єкти класу, але не виконує їх ініціалізацію і не присвоює значення членам класу.

Хоча ви не можете побачити неявно згенерований конструктор, але його існування можна довести:

Вищенаведений код скомпілюється, оскільки в об’єкті date спрацює неявний конструктор (який є відкритим). Якщо ваш клас має інші конструктори, то неявно згенерований конструктор створюватися не буде. Наприклад:

Рекомендується завжди створювати принаймні один конструктор для класу. Це дозволить вам контролювати процес створення об’єктів вашого класу, і запобіжить виникненню потенційних проблем після додання інших конструкторів.

Правило: Створюйте хоча б один конструктор в класі, навіть якщо це пустий конструктор за замовчуванням.

Класи, які містять інші класи

Одні класи можуть містити інші класи в якості змінних-членів. За замовчуванням, при створенні зовнішнього класу, для змінних-членів будуть викликатися конструктори за замовчуванням. Це станеться до того, як тіло конструктора виконається. Наприклад:

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

A
B

При створенні змінної b викликається конструктор B(). Перш ніж тіло конструктора виконається, m_a ініціалізується, викликаючи конструктор за замовчуванням класу A. Таким чином, виведеться A. Потім керування повернеться назад до конструктора B, і тіло конструктора B почне своє виконання.

В цьому є сенс, тому що конструктор B() може захотіти використати змінну m_a, тому спочатку потрібно ініціалізувати m_a!

Тест

Завдання №1

a) Напишіть клас Ball, який повинен мати наступні дві закриті змінні-члени зі значеннями за замовчуванням:

   m_color (Red);

   m_radius (20.0).

У класі Ball повинні бути наступні конструктори:

   для встановлення значення тільки для m_color;

   для встановлення значення тільки для m_radius;

   для встановлення значень і для m_radius, і для m_color;

   для встановлення значень, коли значення не надані взагалі.

Не використовуйте параметри за замовчуванням для конструкторів. Напишіть ще одну функцію для виводу кольору (m_color) і радіусу (m_radius) кулі (об’єкта класу Ball).

Наступний код функції main():

Повинен видати наступний результат:

color: red, radius: 20
color: black, radius: 20
color: red, radius: 30
color: black, radius: 30

Відповідь №1.а)

b) Тепер оновіть ваш код з попереднього завдання з використанням конструкторів з параметрами за замовчуванням. Постарайтеся використовувати якомога менше конструкторів.

Відповідь №1.b)

Завдання №2

Що відбудеться, якщо не оголосити конструктор за замовчуванням?

Відповідь №2

Якщо не визначити ніяких конструкторів, то компілятор автоматично створить пустий відкритий конструктор за замовчуванням. Якщо визначити хоча б один будь-який конструктор (за замовчуванням або інший), то компілятор не створить пустий конструктор за замовчуванням.

Оцінити статтю:

1 Зірка2 Зірки3 Зірки4 Зірки5 Зірок (2 оцінок, середня: 5,00 з 5)
Loading...

Залишити відповідь

Ваш E-mail не буде опублікований. Обов'язкові поля відмічені *