Спецификатор 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(){return5;}};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 {virtualvoid 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) | явно объявляет, что метод переопределяет другой метод |