Урок №125. Список ініціалізації членів класу

  Юрій  | 

  Оновл. 7 Вер 2021  | 

 260

На цьому уроці ми розглянемо, як ініціалізувати змінні-члени класу за допомогою списку ініціалізації в мові С++, а також особливості і нюанси, які при цьому можуть виникнути.

Списки ініціалізації членів класу

На попередньому уроці ми ініціалізували члени нашого класу в конструкторі через оператор присвоювання:

Спочатку створюються m_value1, m_value2 і m_value3. Потім виконується тіло конструктора, де цим змінним присвоюються значення. Аналогічний код в НЕ об’єктно-орієнтованому С++:

Хоча в плані синтаксису мови C++ питань ніяких немає — все коректно, але ефективніше використовувати ініціалізацію, а не присвоювання після оголошення.

Як ми вже знаємо з попередніх уроків, деякі типи даних (наприклад, константи і посилання) повинні бути ініціалізовані відразу. Розглянемо наступний приклад:

Аналогічний код в НЕ об’єктно-орієнтованому C++:

Для вирішення цієї проблеми в C++ додали метод ініціалізації змінних-членів класу через список ініціалізації членів, замість присвоювання їм значень після оголошення. Не плутайте цей список з аналогічним списком ініціалізаторів, який використовується для ініціалізації масивів.

З уроку №31 ми вже знаємо, що ініціалізувати змінні можна трьома способами: через копіюючу ініціалізацію, пряму ініціалізацію або uniform-ініціалізацію.

Використання списку ініціалізації майже ідентичне виконанню прямої ініціалізації (або uniform-ініціалізації в C++11).

Щоб було зрозуміліше, розглянемо приклад. Ось код з присвоюванням значень змінним-членам класу в конструкторі:

Тепер давайте перепишемо цей код, але вже з використанням списку ініціалізації:

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

Values(3, 4.5, d)

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

Можна також додати можливість для caller-а передавати значення для ініціалізації:

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

Values(3, 4.5, d)

Ми можемо використовувати параметри за замовчуванням для надання значень за замовчуванням, якщо користувач їх не надав. Наприклад, клас, який має константну змінну-член:

Це працює, оскільки нам дозволено ініціалізувати константні змінні (але не присвоювати їм значення після оголошення!).

Правило: Використовуйте списки ініціалізації членів, замість операцій присвоювання, для ініціалізації змінних-членів вашого класу.

uniform-ініціалізація в C++11

У C++11 замість прямої ініціалізації можна використовувати uniform-ініціалізацію:

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

Правило: Використовуйте uniformініціалізацію замість прямої ініціалізації в C++11.

Ініціалізація масивів у класі

Розглянемо клас з масивом в якості змінної-члена:

До C++11 ми могли тільки обнулити масив через список ініціалізації:

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

Ініціалізація змінних-членів, які є класами

Список ініціалізації членів також може використовуватися для ініціалізації членів, які є класами:

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

A 6
B 7

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

Використання списків ініціалізації

Якщо список ініціалізації поміщається на тому самому рядку, що і ім’я конструктора, то краще все розмістити в одному рядку:

Якщо список ініціалізації членів не поміщається в рядку з ім’ям конструктора, то на наступному рядку (використовуючи перенесення) ініціалізатори повинні бути з відступом:

Якщо всі ініціалізатори не поміщаються в одному рядку, то ви можете виділити для кожного ініціалізатора окремий рядок:

Порядок виконання в списку ініціалізації

Дивно, але змінні в списку ініціалізації НЕ ініціалізуються в тому порядку, в якому вони вказані. Замість цього вони ініціалізуються в тому порядку, в якому оголошені в класі, тому слід дотримуватися наступних рекомендацій:

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

   Ініціалізуйте змінні в списку ініціалізації в тому порядку, в якому вони оголошені в класі.

Висновки

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

Тест

Напишіть клас з ім’ям RGBA, який містить 4 змінні-члени типу std::uint8_t (підключіть заголовок cstdint для доступу до типу std::uint8_t):

   m_red;

   m_green;

   m_blue;

   m_alpha.

Присвойте 0 в якості значення за замовчуванням для m_red, m_green і m_blue, і 255 для m_alpha. Створіть конструктор зі списком ініціалізації членів, який дозволить користувачу передавати значення для m_red, m_green, m_blue і m_alpha. Напишіть функцію print(), яка виводитиме значення змінних-членів.

Підказка: Якщо функція print() працює некоректно, то переконайтеся, що ви конвертували std::uint8_t в int.

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

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

r=0 g=135 b=135 a=255

Відповідь

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

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

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

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