Как написать финальный класс, чтобы он не мог использоваться в качестве базового класса

Сразу можно ответить, что нужно определить класс со спецификатором final. Этот спецификатор был введен в стандарт С++11. А если компилятор очень старый?.. Или же хочется знать как это делали до 2011 _ го года? Как можно написать класс Target, чтобы он не мог использоваться как базовый, не используя спецификатор final?


Ответы (1 шт):

Автор решения: HolyBlackCat

Вот такой вариант придумал:

template <typename T>
class FinalBase
{
    friend T;
    FinalBase() = default;
    FinalBase(const FinalBase &) = default;
    FinalBase &operator=(const FinalBase &) = default;
};

#ifndef NDEBUG
#define FINAL(...) __VA_ARGS__ : virtual FinalBase<__VA_ARGS__>
#else
#define FINAL(...) __VA_ARGS__
#endif

struct FINAL(A) // Вместо `struct A final`.
{

};

struct B : A
{

};

Здесь, из-за виртуального наследования, конструкторы B будут пытаться вызвать конструкторы FinalBase<A> напрямую. Но не смогут, потому что те приватные.

В коде выше ошибки нет, но она возникнет, если попытаться создать объект B:

error: call to implicitly-deleted default constructor of 'B'
note: default constructor of 'B' is implicitly deleted because base class 'FinalBase<A>' has
    an inaccessible default constructor

Или если попытаться написать конструктор для B:

error: inherited virtual base class 'FinalBase<A>' has private default constructor

Поскольку виртуальное наследование увеличивает размер класса, добавил проверку #ifndef NDEBUG, чтобы отключать его в релизной сборке.

→ Ссылка