final спецификатор (с C++11)
Указывает, что виртуальная функция виртуальная функция не может быть переопределена в производном классе, или что класс не может быть производным.
Синтаксис
При применении к член-функции идентификатор final появляется непосредственно после декларатора в синтаксисе объявления член-функции или определения член-функции внутри определения класса.
При применении к классу идентификатор final появляется в начале определения класса, непосредственно после имени класса.
| декларатор virt-specifier-seq (необязательно) pure-specifier (необязательно) | (1) | |
| декларатор 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: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++.
| 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/w/cpp/language/final