Приватный конструктор в С++

      Комментарии к записи Приватный конструктор в С++ отключены

В этой теме 1 ответ, 2 участника, последнее обновление  Васильев Владимир Сергеевич 1 год, 3 мес. назад.

  • Автор
    Сообщения
  • #2714

    questioner
    Участник

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

  • #2725

    Конструктор помещается в секцию private в случаях, если нужно ограничить пользователя в возможностях создания объектов. Часто так поступают с конструктором копирования, если хотят запретить эту операцию (обычно вместе с этим в приватную секцию помещают оператор присваивания):

    class NonCopyable {
    private:
       NonCopyable(const NonCopyable&) = delete;
       void operator=(const NonCopyable&) = delete;
    };

    Если нужно запретить операцию копирования, то имеет смысл объявить функции с ключевым словом delete или объявить, но не реализовывать, т.к. в противном случае их смогут использовать функции-члены класса, а также функции дружественных классов.
    Чтобы запретить копирование достаточно создать дочерний класс от boost::noncopyable, у которого эти операции приватные.
    Примером такого класса из стандартной библиотеки является fstream, предоставляющий возможность работы с файловыми потоками, кроме того, это могут быть различные классы работы с БД, мьютексами, очень большими объектами, копирование которых не эффективно.

    Кроме того, закрытые конструкторы применяются если для порождения объектов пользователь должен использовать специальную функцию. Эта функция может выполнять ряд дополнительных действий, не допустимых для конструктора. Такой подход применяется в ряде шаблонов проектирования:

    • Singleton [пример использования шаблона Singleton для работы с базой данных], управляет созданием объектов, следит за тем, чтобы существовал только один экземпляр класса, который либо создается, либо возвращается уже готовый. Конструктор должен в любом случае создать объект, поэтому созданием занимается отдельная функция;
    • шаблон «Фабричный метод». Есть различные реализации паттерна, но в любом случае порождением объектов занимается отдельная функция, которая может принимать идентификатор класса, объект которого нужно создать:
      Item Item::factoryMethod(ItemType type) {
        switch (type) {
        case Wall:
          return Wall();
        case Tree:
          return Tree();
        // ...
        }
      }
    • Прототип [пример использования Prototype для реализации меню графического редактора]. Функция, используемая вместо конструктора создает клон существующего объекта и является виртуальной. Конструктор по очевидным причинам не может быть виртуальным.
    • Подход с использованием специальных функций вместо конструктора используется часто если при создании объекта нужно выполнять какие-либо проверки, а возможно — выкинуть исключения. Конструкторы не должны выпускать наружу исключения, т.к. при этом все объекты, находящие на стеке должны разрушится, включая сам, еще не полностью созданный объект, однако объект еще не был окончательно создан, поэтому и деструктор не должен быть вызван.

Для ответа в этой теме необходимо авторизоваться.