Как написать финальный класс, чтобы он не мог использоваться в качестве базового класса
Сразу можно ответить, что нужно определить класс со спецификатором final. Этот спецификатор был введен в стандарт С++11. А если компилятор очень старый?.. Или же хочется знать как это делали до 2011 _ го года? Как можно написать класс Target, чтобы он не мог использоваться как базовый, не используя спецификатор final?
Ответы (1 шт):
Вот такой вариант придумал:
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, чтобы отключать его в релизной сборке.