Списки инициализации конструктора
Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy. Урок 22 из 104.
В предыдущих уроках вы уже видели синтаксис с двоеточием, например Player(std::string n, int h) : name(n), health(h) {}. Это называется списком инициализации членов, и это предпочтительный способ инициализации членов в C++.
Список initializer появляется после списка параметров constructor, начиная с двоеточия. Каждый член initialized напрямую своим значением, разделённым запятыми:
class Rectangle {
int width;
int height;
const int id;
int& reference;
public:
Rectangle(int w, int h, int i, int& r)
: width(w), height(h), id(i), reference(r) {
// Тело конструктора (может быть пустым)
}
};Зачем использовать списки initializer вместо присваивания в теле конструктора? При использовании присваивания члены сначала создаются со значениями по умолчанию, а затем им присваиваются новые значения. При использовании списков initializer члены создаются непосредственно с правильными значениями — это эффективнее и иногда необходимо.
Определённые члены должны быть инициализированы с использованием списка:
- Члены
const— им нельзя присваивать значения после создания
- Ссылочные члены — должны быть связаны при инициализации
- Члены без конструкторов по умолчанию
class Player {
const int maxHealth; // Необходимо использовать список инициализации
std::string name;
public:
// Это работает
Player(int max, std::string n) : maxHealth(max), name(n) {}
// Это НЕ скомпилируется:
// Player(int max) { maxHealth = max; } // Ошибка!
};Члены инициализируются в порядке, в котором они declared в class, а не в порядке списка инициализаторов. Всегда записывай список инициализаторов в порядке объявления, чтобы избежать путаницы.
Задание
ЛегкоДавайте создадим систему configuration для игрового движка, которая демонстрирует, когда и почему списки инициализации членов необходимы. Вы создадите GameConfig class с членами, которые должны быть initialized с использованием синтаксиса списка инициализации.
Вы создадите два файла для организации кода:
GameConfig.h: defineGameConfigclass, который хранит настройки игры. Ваш class должен содержать:const std::string gameName: название игры, которое нельзя изменить после созданияconst int maxPlayers: максимальное количество игроков, фиксированное при созданииint& difficultyRef: ссылку на external настройку сложностиint screenWidthиint screenHeight: обычные члены для настроек display- Constructor, принимающий все необходимые параметры и initialized EVERY член с использованием списка инициализации. Список инициализации должен следовать порядку, в котором члены объявлены в class
- Метод
display(), который выводит configuration в следующем формате:Game: <gameName> Max Players: <maxPlayers> Difficulty: <difficultyRef value> Resolution: <screenWidth>x<screenHeight>
main.cpp: считайте значения configuration из ввода и создайте объект GameConfig. Вам потребуется:- Считать из ввода название игры (string), количество игроков (int), сложность (int), ширину (int) и высоту (int): каждое значение в отдельной строке
- Создать локальную переменную
intдля сложности, на которую будет ссылаться config - Создать объект
GameConfigс использованием Constructor со списком инициализации - Вызвать
display(), чтобы показать initial configuration - Изменить переменную сложности directly (умножить её на 2)
- Вывести
"After difficulty change:" - Снова вызвать
display(), чтобы показать, что ссылка отражает обновлённое значение
Эта задача демонстрирует, почему списки инициализации важны: ваши члены const и член-ссылка cannot быть присвоены в теле Constructor. Они должны быть initialized в списке. Член-ссылка также демонстрирует, как изменения исходной переменной отражаются через объект config.
Подключите header-файл в main.cpp с помощью #include "GameConfig.h".
Попробуйте сами
#include <iostream>
#include <string>
#include "GameConfig.h"
using namespace std;
int main() {
// Прочитать входные значения
string gameName;
getline(cin, gameName);
int maxPlayers;
cin >> maxPlayers;
int difficulty;
cin >> difficulty;
int width;
cin >> width;
int height;
cin >> height;
// TODO: Создайте объект GameConfig, используя конструктор со списком инициализации
// Конструктор должен принимать: gameName, maxPlayers, difficulty (по ссылке), width, height
// TODO: Вызовите display(), чтобы показать начальную конфигурацию
// TODO: Измените переменную difficulty напрямую (умножьте её на 2)
// TODO: Print "After difficulty change:"
// TODO: Вызовите display() снова, чтобы показать обновлённую конфигурацию
return 0;
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыСборка и компиляция C++Заголовочные файлы и файлы исходного кодаПространства имен и область видимостиВведение в ООП на C++Классы и объектыУказатель 'this'Методы (функции-члены)Атрибуты (члены данных)Основы конструкторов и деструкторовИтоги — Простой калькулятор4Свойства классов
Члены экземпляра против статическихГеттеры и сеттерыКонстантные функции-членыКлючевое слово mutableСтатические методы и переменныеДружественные функции и классыИтоги — Менеджер банковских счетов7Наследование
Основы наследованияУровни доступа при наследованииПорядок вызова конструкторов и деструкторовПереопределение методовВиртуальные функции и VTableМножественное наследованиеВиртуальное наследованиеИтоги — Иерархия сотрудников10Обзор STL
Обзор и философия STLКонтейнеры STLИтераторыАлгоритмы STLФункторы и лямбда-выраженияИтоги: частота слов13Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonFactory и Abstract FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy2Управление памятью
Стек и кучаУказатели и ссылкиДинамическая память (new/delete)Умные указатели в C++RAII в C++Итоги — Менеджер динамического массива5Инкапсуляция
Спецификаторы доступа в C++Спецификаторы доступа: подробный разборСокрытие данныхStruct против ClassВложенные и внутренние классыИтоги — Система учета студентов8Полиморфизм
Полиморфизм компиляции и времени выполненияПерегрузка функцийВиртуальные функции: повторениеЧистые виртуальные функцииАбстрактные классыПроектирование интерфейсов на C++Dynamic Casting и RTTIИтоги: Калькулятор фигур11Продвинутые концепции ООП
Композиция против наследованияМиксины через CRTPИдиома PimplСтирание типовEnum Classes и строгая типизацияОбработка исключений в ООППользовательские иерархии исключений14Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикRAII как паттерн3Конструкторы и деструкторы
Конструктор по умолчаниюПараметризованный конструкторКонструктор копированияКонструктор перемещенияСписки инициализации конструктораДелегирующие конструкторыГлубокое погружение в деструкторыПравило трех / пяти / нуляПовторение — класс String6Перегрузка операторов
Введение в перегрузку операторовПерегрузка арифметических операторовПерегрузка операторов сравненияОператоры потоковПерегрузка оператора присваиванияПерегрузка операторов [] и ()Операторы преобразования типовИтоги — класс Matrix9Шаблоны
Шаблоны функцийШаблоны классовСпециализация шаблоновВариативные шаблоныОсновы SFINAE и Type TraitsИтоги — Обобщенный контейнерПотренируйтесь самостоятельно: Онлайн-компилятор C++