Недавно мне задали следующий вопрос:
Вы пишете базовый класс, который вы хотите, чтобы другие люди могли использовать для личного пользования. Вы хотели бы, чтобы никто не смог создать экземпляр Базового класса, который вы пишете (только объекты производных классов).
Как бы вы реализовали этот класс?
Я подумал о двух решениях:
Один из них — сделать базовый класс абстрактным (добавив чисто виртуальную функцию).
Во-вторых, поместите конструктор в защищенный раздел, чтобы никто снаружи не смог создать его экземпляр, только производные классы.
Мой вопрос: в чем разница между моими решениями (во всех аспектах, которые вы можете придумать)?
Благодарю.
Защищенный конструктор имеет смысл, но не мешает созданию экземпляра класса:
class Foo
{
protected:
Foo() = default;
public:
static Foo make() { return Foo(); }
};
int main()
{
auto f = Foo::make();
}
С другой стороны, абстрактный класс никогда не может быть создан, чего вы можете здесь пожелать.
Однако важный вопрос заключается в том, нужен ли вам полиморфный иерархия, в которой вам нужно выбирать типы во время выполнения и обрабатывать разнородную коллекцию объектов с помощью базовых указателей. Если так, то абстрактная база — это путь. Если нет, у вас не может быть абстрактного класса без виртуальных функций, и защищенный конструктор (и деструктор) — это единственный способ сообщить о том, что вы хотите создать непостижимую базу.
Чистая виртуальная функция добавляет накладные расходы таблицы виртуальных функций к вашему базовому классу, что может быть проблемой, если вам нужно, чтобы объекты были действительно маленькими. Этого можно избежать, используя защищенные конструкторы и / или защищенный деструктор. Защищенный деструктор полезен для предотвращения случайного удаления с помощью указателя базового класса, который при отсутствии виртуальный деструктор, приведет к неопределенному поведению.