Является ли публичный конструктор абстрактного класса кодовым кодом?

Является ли публичный конструктор абстрактного класса кодовым кодом? Обеспечение защиты конструктора обеспечивает весь доступ, доступ к которому вы можете использовать. Единственным дополнительным доступом, который делает его общедоступным, было бы разрешить экземпляры класса объявляться как переменные в областях, которые не могут получить доступ к его защищенным членам, но экземпляры абстрактных классов не могут быть объявлены вообще.

Ответ 1

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

Фактически, вам нужно только объявить конструктор в абстрактном классе, если ему нужно что-то сделать, например. инициализировать своих частных членов. Тогда я ожидал, что там будут другие защищенные функции-члены, которые полезны для производных классов.

EDIT:

Поскольку никто не опубликовал какой-либо код, а @sbi попросил кого-нибудь в комментарии к OP, я подумал, что отправлю некоторые из них:

class Base:
{
public:           // The question is: should the ctor be public or protected?
// protected:
    Base():i(0){} // ctor is necessary to initialise private member variable
public:
    virtual ~Base(){} // dtor is virtual (but thats another story)
                  // pure virtual method renders the whole class abstract
    virtual void setValue(void)=0;  
protected:
    int getValue(void){ return i;}
private:
    int i;
};

Base b1;  // Illegal since Base is abstract, even if ctor is public
Base& b2=makeBase();  //We can point to, or refer to a Base
b2.setValue();    // We're not sure what this does, but we can call it.
b2.getValue();    // Illegal since getValue is protected

Ответ 2

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

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

Ответ 3

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

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

Ответ 4

Абстрактный класс никогда не может быть непосредственно создан из-за чистых виртуальных методов, которые он объявляет. Таким образом, объявление конструктора как защищенного просто добавляет дополнительные советы для программистов.

Я видел рекомендацию объявить конструктор как защищенный здесь, в руководстве по стилю Google. И я встречал аналогичные рекомендации в некоторых других стандартах корпоративного кодирования. Таким образом, это выглядит как хорошая практика.

Ответ 5

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

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

Или, другими словами, если вы меняете интерфейс, почему вы в первую очередь получаете этот класс?

Это немного религиозный ответ, но что, черт возьми.; -)

Ответ 6

Ответ для современного C++

Однако я наталкиваюсь на старую ветку:

  • это первый вопрос, который возник у меня при поиске разницы между public и protected конструкторами в абстрактных классах,
  • новые стандарты C++, опубликованные после того, как на этот вопрос был задан и дан ответ, изменили "правильный" ответ.

Резюме

public конструкторы в абстрактных классах не являются запахом кода. Из-за того, как работают модификаторы доступа унаследованных конструкторов, наличие public и protected конструктора не эквивалентно. public конструкторы в абстрактных классах добавляют больше прав доступа, чем protected.


объяснение

В проекте стандарта N4659, 10.3.3/19 указано, что:

Синоним, созданный объявлением использования, имеет обычную доступность для объявления члена. Использование-декларатор, который называет конструктор, не создает синоним; вместо этого дополнительные конструкторы доступны, если они будут доступны при использовании для создания объекта соответствующего базового класса, а доступность объявления using игнорируется.

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

Вот минимальный пример [ Godbolt ]:

class AbstractPublicCtor {
public:
    virtual void foo() = 0;
    AbstractPublicCtor(int) {}
};

class AbstractProtectedCtor {
public:
    virtual void foo() = 0;
protected:
    AbstractProtectedCtor(int) {}
};

class PublicCtor : public AbstractPublicCtor {
public:
    using AbstractPublicCtor::AbstractPublicCtor;
    void foo() override {}
};

class ProtectedCtor : public AbstractProtectedCtor {
public:
    using AbstractProtectedCtor::AbstractProtectedCtor;
    void foo() override {}
};

int main() {
    PublicCtor x(5);  // works
    ProtectedCtor y(6); // fails to compile 
}

Практическое правило

  • Используйте public конструкторы, если у разработчиков абстрактного класса должны быть public конструкторы, а конструктор базового класса является подходящим кандидатом для public конструктора реализатора.
  • В противном случае используйте protected конструкторы (например, когда конструкторы создаются с использованием фабрики).

Примечание: это моё личное мнение, я с удовольствием его обсуждаю в комментариях.

Ответ 7

Я бы сказал, что это плохой признак по нескольким причинам.

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

Во-вторых, это означает, что автор думал, что вы можете его назвать. Теперь вы не знаете, было ли это важной частью его дизайна или нет.

Ответ 8

Будьте осторожны, хотя явным образом объявляю/определяю ваш защищенный/закрытый конструктор копирования. Если вы этого не сделаете, компилятор сделает это за вас. См. Scott meyers эффективный С++, пункт 6.