Menu
Coddy logo textTech

Списки инициализации конструктора

Часть раздела Объектно-ориентированное программирование путешествия по 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, а не в порядке списка инициализаторов. Всегда записывай список инициализаторов в порядке объявления, чтобы избежать путаницы.

challenge icon

Задание

Легко

Давайте создадим систему configuration для игрового движка, которая демонстрирует, когда и почему списки инициализации членов необходимы. Вы создадите GameConfig class с членами, которые должны быть initialized с использованием синтаксиса списка инициализации.

Вы создадите два файла для организации кода:

  • GameConfig.h: define GameConfig class, который хранит настройки игры. Ваш 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;
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор C++