Урок 117. Список инициализации членов класса

   | 

   | 

 Обновлено 22 Фев 2018  | 

 4091

В предыдущем уроке мы инициализировали члены нашего класса в конструкторе через оператор присваивания:

Сначала создаются m_value1, m_value2 и m_value3. Затем выполняется тело конструктора, где этим переменным присваиваются значения. Аналогичен код в не объектно-ориентированном C++:

Хотя в плане синтаксиса языка C++ вопросов нет – всё корректно, но было бы более эффективно, если бы мы использовали инициализацию, а не присваивание после объявления.

Как мы уже знаем из предыдущих уроков, некоторые типы данных (например, const и ссылки) должны быть инициализированы сразу. Рассмотрим следующий пример:

Аналогичен код в не объектно-ориентированном C++:

Списки инициализации членов класса

Для решения этой проблемы в C++ добавили метод инициализации переменных-членов класса (вместо присваивания им значений после объявления) через список инициализации членов (или список инициализаторов членов). Не путайте этот список с аналогичным списком инициализаторов, который используется для инициализации массивов.

В уроке 28 мы узнали, что инициализировать переменные можно тремя способами: через копирующую, прямую или uniform инициализацию (C++11).

Использование списка инициализации почти идентично выполнению прямой инициализации (или 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».

Использование списков инициализации

Если список инициализации помещается на той же строке, что и имя конструктора, то лучше всё разместить в одной строке:

Если список инициализаторов не помещается в строке, где находится имя конструктора, то на следующей строке (используя перенос) инициализаторы должны быть с отступом.

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

Порядок выполнения инициализаторов в списке инициализации

Удивительно, но переменные в списке инициализаторов не инициализируются в том порядке, в котором они указаны в списке инициализации. Вместо этого они инициализируются в том порядке, в котором объявлены в классе.

Поэтому следует соблюдать следующие рекомендации:

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

  Инициализируйте переменные в списке инициализации в том порядке, в котором они объявлены в классе.

Итого

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

Тест

1. Напишите класс с именем RGBA, который содержит 4 переменные-члены типа std::uint8_t: m_red, m_green, m_blue и m_alpha (#include cstdint для доступа к типу std::uint8_t). Задайте 0 в качестве значения по умолчанию для m_red, m_green, m_blue и 255 для m_alpha. Создайте конструктор со списком инициализации членов, который позволит пользователю передавать значения для m_red, m_blue, m_green и m_alpha. Напишите функцию print(), которая будет выводить значения переменных-членов.

Если вам нужно напоминание о том, как использовать типы int фиксированного размера — смотрите урок 32.

Подсказка: Если функция print() работает некорректно, убедитесь, что вы конвертировали uint8_t в int.

Следующий код функции main():

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

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

Ответ 1

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (23 оценок, среднее: 5,00 из 5)
Загрузка...
Подписаться на обновления:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

ПОДПИСЫВАЙТЕСЬ

НА КАНАЛ RAVESLI В TELEGRAM

@ravesli

ПОДПИСАТЬСЯ БЕСПЛАТНО