Menu
Coddy logo textTech

Делегирующие конструкторы

Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy — урок 23 из 104.

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

class Player {
    std::string name;
    int health;
    int level;
public:
    // Основной конструктор - выполняет фактическую работу
    Player(std::string n, int h, int lvl) 
        : name(n), health(h), level(lvl) {}
    
    // Делегирует основному конструктору
    Player(std::string n) : Player(n, 100, 1) {}
    
    // Конструктор по умолчанию тоже делегирует
    Player() : Player("Unknown") {}
};

Делегирование происходит в списке инициализации с использованием имени класса, за которым следуют аргументы. Когда вызывается Player(), он делегирует выполнение Player(std::string), который, в свою очередь, делегирует выполнение конструктору с тремя параметрами. Цепочка выполняется от целевого конструктора обратно к исходному.

Есть одно важное правило: делегирующий конструктор не может иметь других членов в своем списке инициализации. Делегирование должно быть единственным элементом:

class Item {
    int id;
    int value;
public:
    Item(int i, int v) : id(i), value(v) {}
    
    // Ошибка! Нельзя смешивать делегирование с инициализацией членов
    // Item(int i) : Item(i, 0), id(i) {}
    
    // Правильно — только делегирование
    Item(int i) : Item(i, 0) {}
};

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

challenge icon

Задание

Легко

Давайте создадим систему настроек соединения, которая демонстрирует, как делегирующие конструкторы могут устранить дублирование кода путем связывания вызовов конструкторов в цепочку.

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

  • Connection.h: Определите класс Connection, который представляет сетевое соединение с различными параметрами конфигурации. Ваш класс должен иметь:
    • Приватные члены: host (string), port (int), timeout (int в секундах) и secure (bool)
    • Основной конструктор, который принимает все четыре параметра и инициализирует все члены с помощью списка инициализации. Этот конструктор должен выводить "Connection configured: <host>:<port>"
    • Конструктор, принимающий только host и port, который делегирует выполнение основному конструктору, при этом timeout по умолчанию равен 30, а secure по умолчанию равен false
    • Конструктор, принимающий только host, который делегирует выполнение конструктору с двумя параметрами, при этом port по умолчанию равен 80
    • Конструктор по умолчанию, который делегирует выполнение конструктору с одним параметром, при этом host по умолчанию равен "localhost"
    • Метод getInfo(), который возвращает строку в формате: "<host>:<port> (timeout: <timeout>s, secure: <yes/no>)"
  • main.cpp: Продемонстрируйте цепочку делегирования, создав соединения с использованием различных конструкторов. Считайте имя хоста и номер порта из входных данных (каждое на отдельной строке), затем:
    • Создайте объект Connection, используя конструктор по умолчанию
    • Создайте объект Connection, используя только хост из входных данных
    • Создайте объект Connection, используя и хост, и порт из входных данных
    • Создайте объект Connection с входным хостом, входным портом, таймаутом 60 и параметром secure, установленным в true
    • Выведите результат getInfo() для каждого соединения, по одному на строку

Цепочка делегирования работает следующим образом: конструктор по умолчанию вызывает конструктор с одним параметром, который вызывает конструктор с двумя параметрами, который, в свою очередь, вызывает основной конструктор с четырьмя параметрами. Это означает, что сообщение "Connection configured" выводится один раз для каждого созданного объекта, всегда из основного конструктора.

Для статуса безопасности в getInfo() выводите "yes", если secure равно true, в противном случае — "no".

Подключите ваш заголовочный файл в main.cpp с помощью #include "Connection.h".

Шпаргалка

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

class Player {
    std::string name;
    int health;
    int level;
public:
    // Основной конструктор
    Player(std::string n, int h, int lvl) 
        : name(n), health(h), level(lvl) {}
    
    // Делегирует основному конструктору
    Player(std::string n) : Player(n, 100, 1) {}
    
    // Конструктор по умолчанию тоже делегирует
    Player() : Player("Unknown") {}
};

Делегирование происходит в списке инициализации с использованием имени класса, за которым следуют аргументы. Конструкторы могут образовывать цепочку делегирования, где один делегирует другому.

Важное правило: Делегирующий конструктор не может содержать другие члены в своем списке инициализации. Делегирование должно быть единственным элементом:

class Item {
    int id;
    int value;
public:
    Item(int i, int v) : id(i), value(v) {}
    
    // Ошибка! Нельзя смешивать делегирование с инициализацией членов
    // Item(int i) : Item(i, 0), id(i) {}
    
    // Правильно — только делегирование
    Item(int i) : Item(i, 0) {}
};

Попробуйте сами

#include <iostream>
#include <string>
#include "Connection.h"

using namespace std;

int main() {
    // Чтение входных данных
    string host;
    int port;
    cin >> host;
    cin >> port;

    // TODO: Создать Connection, используя конструктор по умолчанию

    // TODO: Создать Connection, используя только host из входных данных

    // TODO: Создать Connection, используя и host, и port из входных данных

    // TODO: Создать Connection с входными host, port, timeout=60, secure=true

    // TODO: Вывести getInfo() для каждого соединения, по одному на строку

    return 0;
}
quiz iconПроверьте себя

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

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