final спецификатор (начиная с C++11)
Указывает, что виртуальную функцию нельзя переопределить в производном классе или что от класса нельзя унаследоваться.
Синтаксис
При применении к функции-члену идентификатор final располагается непосредственно после декларатора в синтаксисе объявления функции-члена или определения функции-члена внутри определения класса.
При применении к классу (включая структуру и объединение) идентификатор 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) |
final может находиться в virt-specifier-seq непосредственно после декларатора и перед pure-specifier, если он используется.final может находиться в virt-specifier-seq непосредственно после декларатора и прямо перед function-body.final может использоваться как class-virt-specifier непосредственно после имени класса, прямо перед двоеточием, с которого начинается base-clause, если он используется.В случаях (1,2) virt-specifier-seq, если используется, — это либо override, либо final, либо final override, либо override final. В случае (3) единственное допустимое значение class-virt-specifier, если он используется, — final.
Пояснение
При использовании в объявлении или определении виртуальной функции спецификатор final гарантирует, что функция является виртуальной, и указывает, что производные классы не могут её переопределить. В противном случае программа некорректна (возникает ошибка компиляции).
При использовании в определении класса final указывает, что этот класс не может находиться в списке base-specifier-list другого определения класса (иными словами, от него нельзя наследоваться). В противном случае программа некорректна (возникает ошибка компиляции). final также можно использовать с определением объединения; в этом случае он не оказывает никакого эффекта (кроме влияния на результат std::is_final)(начиная с C++14), поскольку от объединений нельзя наследоваться.
final — это идентификатор, имеющий специальное значение при использовании в объявлении функции-члена или заголовке класса. В других контекстах он не зарезервирован и может использоваться для именования объектов и функций.
Примечание
В последовательности следующих токенов:
- один из class, struct и union
- возможно, квалифицированный идентификатор
- final
- один из
:и{
третий токен final в последовательности всегда рассматривается как спецификатор, а не как идентификатор.
struct A;
struct A final {}; // OK, definition of struct A,
// not value-initialization of variable final
struct X
{
struct C { constexpr operator int() { return 5; } };
struct B final : C{}; // OK, definition of nested class B,
// not declaration of a bit-field member final
};
// Abnormal final usage.
struct final final // OK, definition of a struct named “final” from which
{ // you cannot inherit
};
// struct final final {}; // Error: redefinition of “struct final”, NOT a
// definition of a variable “final” using an elaborated
// type specifier “struct final” followed by an
// aggregate initialization
// struct override : final {}; // Error: cannot derive from final base type;
// “override” in given context is a normal name
void foo()
{
[[maybe_unused]]
final final; // OK, declaration of a variable named “final” of type
// “struct final”
}
struct final final; // OK, declaration of a variable named “final” of type
// “struct final” using an elaborated type specifier
int main()
{
}
Ключевые слова
Пример
struct Base
{
virtual void foo();
};
struct A : Base
{
void foo() final; // Base::foo is overridden and A::foo is the final override
void bar() final; // Error: bar cannot be final as it is non-virtual
};
struct B final : A // struct B is final
{
void foo() override; // Error: foo cannot be overridden as it is final in A
};
struct C : B {}; // Error: B is 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) | явно объявляет, что метод переопределяет другой метод |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/language/final