Спецификатор final
(начиная с C++11)
Указывает, что виртуальная функция не может быть переопределена в производном классе или что класс не может наследоваться.
Содержание |
[править] Синтаксис
При применении к функции-элементу идентификатор final
появляется сразу после декларатора в синтаксисе объявления функции-элемента или определения функции-элемента внутри определения класса.
Применительно к классу идентификатор final
появляется в начале определения класса, сразу после имени класса.
декларатор последовательность-спецификаторов-виртуальности (необязательно) чистый-спецификатор (необязательно) | (1) | ||||||||
декларатор последовательность-спецификаторов-виртуальности (необязательно) тело-функции | (2) | ||||||||
ключевое-слово-класса атрибуты (необязательно) имя-заголовка-класса спецификатор-виртуальности-класса (необязательно) предложен��е-базы (необязательно) | (3) | ||||||||
final
может появиться в последовательности-спецификаторов-виртуальности сразу после декларатора и перед чистым-спецификатором, если используется.final
может появиться в последовательности-спецификаторов-виртуальности сразу после декларатора и непосредственно перед телом-функции.final
может отображаться как спецификатор-виртуальности-класса сразу после имени класса, прямо перед двоеточием, с которого начинается предложение-базы, если используе��ся.В случаях (1,2) последовательность-спецификаторов-виртуальности, если она используется, равна либо override
, либо final
, либо final override
или override final
. В случае (3) единственным допустимым значением спецификатора-виртуальности-класса, если он используется, является final
.
[править] Объяснение
При использовании в объявлении или определении виртуальной ��ункции спецификатор final
гарантирует, что функция является виртуальной, и указывает, что она не может быть переопределена производными классами. В противном случае программа некорректна (генерируется ошибка времени компиляции).
При использовании в определении класса final
указывает, что этот класс не может появляться в списке-базовых-спецификаторов другого определения класса (другими словами, не может наследоваться). В противном случае программа некорректна (генерируется ошибка времени компиляции). final
также можно использовать с определением union, и в этом случае оно не будет иметь никакого эффекта (кроме результата std::is_final) (начиная с C++14), поскольку объединения не могут наследоваться.
final это идентификатор со специальным значением при использовании в объявлении функции-элемента или заголовке класса. В других контекстах он не зарезервирован и может использоваться для обозначения объектов и функций.
[править] Примечание
В последовательности следующих токенов:
- один из class, struct и union;
- возможно квалифицированный идентификатор;
- final;
- один из : и {,
третий токен final в последовательности всегда считается спецификатором, а не идентификатором:
struct A; struct A final {}; // ОК, определение структуры A, а не // инициализация значения переменной final struct X { struct C { constexpr operator int() { return 5; } }; struct B final : C{}; // ОК, определение вложенного класса B, // а не объявление элемента битового поля final }; // Ненормальное использование final. struct final final // ОК, определение структуры с именем `final`, { // от которой вы не можете наследовать }; // struct final final {}; // Ошибка: переопределение `struct final`, а НЕ // определение переменной `final` с использованием // сложного спецификатора типа `struct final`, // за которым следует агрегатная инициализация // struct override : final {}; // Ошибка: не может быть выведен базового типа final; // `override` в данном контексте является обычным именем void foo() { [[maybe_unused]] final final; // ОК, объявление переменной с именем `final` // типа `struct final` } struct final final; // ОК, объявление переменной с именем `final` типа // `struct final` с использованием сложного спецификатора типа int main() { }
[править] Пример
struct Base { virtual void foo(); }; struct A : Base { void foo() final; // Base::foo переопределяется, а A::foo // является окончательным переопределением void bar() final; // Ошибка: bar не может быть окончательной, // так как она не виртуальная }; struct B final : A // структура B является окончательной { void foo() override; // Ошибка: foo не может быть переопределена, // так как она является окончательной в A }; struct C : B {}; // Ошибка: B является окончательным
Возможный вывод:
main.cpp:9:10: error: 'void A::bar()' marked 'final', but is not virtual 9 | void bar() final; // Ошибка: не может быть окончательной, // так как она не виртуальная | ^~~ main.cpp:14:10: error: virtual function 'virtual void B::foo()' overriding final function 14 | void foo() override; // Ошибка: foo не может быть переопределена, // так как она является окончательной в A | ^~~ main.cpp:8:10: note: overridden function is 'virtual void A::foo()' 8 | void foo() final; // Base::foo переопределяется, а A::foo // является окончательным переопределением | ^~~ main.cpp:17:8: error: cannot derive from 'final' base 'B' in derived type 'C' 17 | struct C : B // Ошибка: B является окончательным |
[править] Ссылки
- C++23 стандарт (ISO/IEC 14882:2023):
- 11 Классы [class]
- 11.7.3 Виртуальные функции [class.virtual]
- C++20 стандарт (ISO/IEC 14882:2020):
- 11 Классы [class]
- 11.7.2 Виртуальные функции [class.virtual]
- C++17 стандарт (ISO/IEC 14882:2017):
- 12 Классы [class]
- 13.3 Виртуальные функции [class.virtual]
- C++14 стандарт (ISO/IEC 14882:2014):
- 9 Классы [class]
- 10.3 Виртуальные функции [class.virtual]
- C++11 стандарт (ISO/IEC 14882:2011):
- 9 Классы [class]
- 10.3 Виртуальные функции [class.virtual]
[править] Отчёты о дефектах
Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:
Номер | Применён | Поведение в стандарте | Корректное поведение |
---|---|---|---|
CWG 1318 | C++11 | определение класса, которое имеет final после имени класса и пустой список спецификаций элементов, может сделать final идентификатором |
final в этом случае всегда является спецификатором |
[править] Смотрите также
спецификатор override (C++11)
|
явно объявляет, что метод переопределяет другой метод |