Каковы практические применения защищенного конструктора? - PullRequest
75 голосов
/ 29 июня 2009

Зачем кому-то объявлять конструктор защищенным? Я знаю, что конструкторы объявлены закрытыми, чтобы не допустить их создания в стеке.

Ответы [ 9 ]

93 голосов
/ 29 июня 2009

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

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

9 голосов
/ 30 июня 2009

Закрытые конструкторы полезны, когда существуют требования к конструкции, которые не могут быть гарантированы только конструктором. Например, если метод инициализации должен быть вызван сразу после конструктора, или если объект должен зарегистрировать себя в каком-либо объекте контейнера / менеджера, это должно быть сделано вне конструктора. Ограничивая доступ к конструктору и предоставляя только фабричный метод, вы можете гарантировать, что любой экземпляр, который получает пользователь, будет выполнять все свои гарантии. Это также обычно используется для реализации Singleton, что на самом деле является еще одной гарантией, которую дает класс (что будет только один экземпляр).

Причина создания защищенного конструктора, а не частного, та же, что и для создания любого другого метода или поля, защищенного вместо частного: так, чтобы он мог наследоваться дочерними элементами. Возможно, вам нужен открытый, не виртуальный фабричный метод в базовом классе, который возвращает ссылки на экземпляры производных классов; производные классы, очевидно, хотят получить доступ к родительским конструкторам, но вы все равно не хотите создавать их вне вашей фабрики.

9 голосов
/ 29 июня 2009

одно использование может быть фабричным образцом

7 голосов
/ 10 ноября 2010

Защищенный конструктор может использоваться для эффективного абстрагирования класса, если ни один из его методов не является чисто виртуальным.

Это не совсем абстрактно в смысле C ++, поскольку классы-друзья могут использовать его без переопределения, но тогда вам придется объявить их.

6 голосов
/ 29 июня 2009

Защищенный конструктор означает, что только производные члены могут создавать экземпляры класса (и производные экземпляры) с использованием этого конструктора. Это звучит немного глупо, но иногда полезно при реализации фабрик классов.

5 голосов
/ 30 июня 2009

Для заводских методов с побочными эффектами.

class mine {

  private:
    mine () {};

  protected:
    mine(int id) : m_id(id) {};

   int m_id;
   static int m_count;

  public:
    static mine* CreateOneOfMe() {
         return mine(m_count++);
    }

    int GetId() { return m_id; }

 };

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

4 голосов
/ 29 июня 2009

Чтобы позволить подклассу использовать конструктор, который не должен быть доступен для экземпляра напрямую.

3 голосов
/ 29 июня 2009

Вы можете использовать его для ограничения классов, которые могут его создать, например:

class Level
{
private:

 Level();
 ¨Level();

 friend class LevelManager;
};

Единственный класс, который может создать его экземпляр, это класс LevelManager, поэтому вы всегда будете знать, что экземпляр Level создан в LevelManager.

0 голосов
/ 30 марта 2019

Одно из применений защищенного конструктора - реализация шаблона CRTP, см. Код ниже:

#include <iostream>
#include <assert.h>

template <class T>
class ComparableMixin {
public:
    bool operator !=(ComparableMixin &other) {
        return ~(*static_cast<T*>(this) == static_cast<T&>(other));
    }
    bool operator <(ComparableMixin &other) {
        return ((*(this) != other) && (*static_cast<T*>(this) <= static_cast<T&>(other)));
    }
    bool operator >(ComparableMixin &other) {
        return ~(*static_cast<T*>(this) <= static_cast<T&>(other));
    }
    bool operator >=(ComparableMixin &other) {
        return ((*static_cast<T*>(this) == static_cast<T&>(other)) || (*(this) > other));
    }
protected:
    ComparableMixin() {}
};

class Integer: public ComparableMixin<Integer> {
public:
 Integer(int i) {
     this->i = i;
 }
 int i;
 bool operator <=(Integer &other) {
     return (this->i <= other.i);
 }
 bool operator ==(Integer &other) {
     return (this->i == other.i);
 }
};
int main() {

    Integer i(0) ;
    Integer j(1) ;
    //ComparableMixin<Integer> c; //compilation error!
    assert (i < j );
    assert (i != j);
    assert (j >  i);
    assert (j >= i);

    return 0;
}
...