final
specifier
(since C++11)
Указывает, что виртуальная функция не может быть переопределена в производном классе, или что класс не может быть унаследован .
Содержание |
Синтаксис
При применении к функции-члену идентификатор
final
указывается непосредственно после
декларатора
в синтаксисе объявления функции-члена или определения функции-члена внутри определения класса.
При применении к классу (включая struct и union), идентификатор
final
указывается в начале определения класса, непосредственно после имени класса, и не может появляться в объявлении класса.
| declarator virt-specifier-seq (необязательно) pure-specifier (необязательно) | (1) | ||||||||
| declarator virt-specifier-seq (необязательно) function-body | (2) | ||||||||
| class-key attr (необязательно) class-head-name class-virt-specifier (необязательно) base-clause (необязательно) | (3) | (до C++26) | |||||||
| class-key attr (необязательно) class-head-name class-prop-specifier-seq (необязательно) base-clause (необязательно) | (4) | (начиная с C++26) | |||||||
final
может появляться в
virt-specifier-seq
сразу после декларатора и перед
pure-specifier
, если он используется.
final
может появляться в
virt-specifier-seq
сразу после декларатора и непосредственно перед
function-body
.
final
может использоваться как
class-virt-specifier
непосредственно после имени класса, непосредственно перед двоеточием, начинающим
base-clause
, если он используется.
final
может появляться в
class-prop-specifier-seq
, если используется, но только один раз.
В случаях
(1,2)
,
virt-specifier-seq
, если используется, может быть либо
override
, либо
final
, либо
final override
, либо
override final
. В случае
(3)
единственным допустимым значением
class-virt-specifier
, если используется, является
final
. В случае
(4)
,
class-prop-specifier-seq
, если используется, может содержать любое количество
спецификаторов свойств класса
(начиная с C++26)
, но каждый может встречаться не более одного раза.
Объяснение
При использовании в объявлении или определении виртуальной функции, final спецификатор гарантирует, что функция является виртуальной и указывает, что она не может быть переопределена производными классами. В противном случае программа является некорректной (генерируется ошибка времени компиляции).
При использовании в определении класса, final указывает, что этот класс не может появляться в base-specifier-list другого определения класса (другими словами, не может быть унаследован). В противном случае программа некорректна (генерируется ошибка компиляции). final также может использоваться с определением union , в этом случае он не имеет эффекта (кроме влияния на результат std::is_final ) (начиная с C++14) , поскольку объединения не могут быть унаследованы.
final — это идентификатор со специальным значением при использовании в объявлении функции-члена или заголовке класса. В других контекстах он не зарезервирован и может использоваться для именования объектов и функций.
Примечание
В последовательности следующих токенов:
- один из class , struct и union
- возможно квалифицированный идентификатор
- final
- один из : и {
третий токен final в последовательности всегда рассматривается как спецификатор, а не идентификатор.
struct A; struct A final {}; // OK, определение структуры A, // не инициализация переменной final struct X { struct C { constexpr operator int() { return 5; } }; struct B final : C{}; // OK, определение вложенного класса B, // не объявление битового поля final }; // Нетипичное использование final. struct final final // OK, определение структуры с именем `final`, от которой { // нельзя наследоваться }; // struct final final {}; // Ошибка: переопределение `struct final`, НЕ // определение переменной `final` с использованием // уточненного спецификатора типа `struct final` // с последующей агрегатной инициализацией // struct override : final {}; // Ошибка: нельзя наследовать от final базового типа; // `override` в данном контексте является обычным именем void foo() { [[maybe_unused]] final final; // OK, объявление переменной с именем `final` типа // `struct final` } struct final final; // OK, объявление переменной с именем `final` типа // `struct final` с использованием уточненного спецификатора типа int main() { }
Ключевые слова
Пример
struct Base { virtual void foo(); }; struct A : Base { void foo() final; // Base::foo переопределена и A::foo является финальным переопределением void bar() final; // Ошибка: bar не может быть final, так как не является виртуальной }; struct B final : A // struct B является final { void foo() override; // Ошибка: foo не может быть переопределена, так как она final в A }; struct C : B {}; // Ошибка: B является final
Возможный вывод:
main.cpp:9:10: error: 'void A::bar()' marked 'final', but is not virtual
9 | void bar() final; // Error: bar cannot be final as it is non-virtual
| ^~~
main.cpp:14:10: error: virtual function 'virtual void B::foo()' overriding final function
14 | void foo() override; // Error: foo cannot be overridden as it is final in A
| ^~~
main.cpp:8:10: note: overridden function is 'virtual void A::foo()'
8 | void foo() final; // Base::foo is overridden and A::foo is the final override
| ^~~
main.cpp:17:8: error: cannot derive from 'final' base 'B' in derived type 'C'
17 | struct C : B // Error: B is final
|
Ссылки
- Стандарт C++23 (ISO/IEC 14882:2024):
-
- 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++.
| DR | Применяется к | Поведение как опубликовано | Корректное поведение |
|---|---|---|---|
| CWG 1318 | C++11 |
определение класса, которое имеет
final
после имени класса и пустой
список спецификаций членов может сделать final идентификатором |
final
всегда является
спецификатором в этом случае |
Смотрите также
override
спецификатор
(C++11)
|
явно объявляет, что метод переопределяет другой метод |
| спецификаторы свойств класса (C++26) | final спецификатор (C++11) , заменяемость (C++26) , тривиальная перемещаемость (C++26) |