Как запретить наследование от класса в C++

Ответ

В C++ есть два основных способа запретить наследование от класса.

1. Использование ключевого слова final (C++11 и новее) Это самый простой и рекомендуемый современный способ. Ключевое слово final указывается после имени класса.

class Base final { // Класс помечен как final
    // ... содержимое класса ...
};

class Derived : public Base { // Ошибка компиляции: cannot derive from 'final' base
};

2. Использование приватного конструктора и friend-класса (до C++11) Этот метод работает в любом стандарте, но сложнее. Конструктор делается приватным, а для создания экземпляров используется статический метод или friend-класс.

class NonInheritable {
private:
    NonInheritable() {} // Приватный конструктор
public:
    // Фабричный метод для создания экземпляров
    static NonInheritable createInstance() {
        return NonInheritable();
    }
};

class Derived : public NonInheritable { // Ошибка: 'NonInheritable::NonInheritable()' is private
};

int main() {
    auto obj = NonInheritable::createInstance(); // OK
    // NonInheritable obj2; // Ошибка: конструктор приватный
}

Вывод: Для новых проектов используйте final. Старый метод с приватным конструктором полезен для поддержки legacy-кода или создания паттерна типа Singleton.

Ответ 18+ 🔞

А, ну это классика, ёпта! Ситуация, когда ты написал класс, а потом какой-нибудь распиздяй решает от него унаследоваться и всё поломать. Волнение ебать! Хочется взять и впендюрить ему в голову, что не всё в этом мире нужно плодить и размножать. К счастью, в C++ есть пара способов поставить на этом деле жирный крест.

1. Волшебное слово final (C++11 и новее) Это как надеть на класс противозачаточный колпак, ёбааать. Просто, элегантно, и никаких неожиданных наследников. Пишешь final после имени класса — и всё, приехали. Компилятор сам всех разгонит.

class Base final { // Всё, приплыли. Этот класс — тупиковая ветвь эволюции.
    // ... что там у тебя внутри ...
};

class Derived : public Base { // Ошибка компиляции! Нельзя наследоваться от 'final' класса.
    // Чувак, тебе только что сказали "иди на хуй" на уровне языка.
};

2. Старый дедовский способ с приватным конструктором (для тех, кто живёт как будто в 2002-м) Это для мазохистов или для ситуаций, когда твой компилятор древнее мамонта. Суть в том, чтобы спрятать конструктор так далеко, что до него никто не доберётся. Наследник не сможет его вызвать — и накрылся медным тазом вся идея наследования. Правда, и самому классу создавать себя становится проблематично, приходится выкручиваться через статические методы или friend-классы. Пизда рулю удобству, но работает.

class NonInheritable {
private:
    NonInheritable() {} // Конструктор спрятан. Хуй с горы тебе, наследничек.
public:
    // Приходится городить огород, чтобы хоть как-то себя создать.
    static NonInheritable createInstance() {
        return NonInheritable(); // А тут можно, мы же внутри класса.
    }
};

class Derived : public NonInheritable { // Ошибка! Конструктор базы приватный, ты его не вызовешь.
    // Сам от себя охуел, да?
};

int main() {
    auto obj = NonInheritable::createInstance(); // Ок, создали через фабрику.
    // NonInheritable obj2; // А вот так уже низя, конструктор-то приватный. Подозрение ебать чувствую к такому коду.
}

Итог, чувак: Если у тебя не каменный век, жми final и не парься. Это ядрёно удобно и понятно всем. Старый метод с приватным конструктором — это такой музейный экспонат, на который можно посмотреть, вспомнить, как страдали предки, и поблагодарить стандарт C++11 за то, что избавил нас от этого геморроя.