Пространства имён
Варианты
Действия

Спецификатор final(начиная с C++11)

Материал из cppreference.com
< cpp‎ | language
 
 
 
 

Указывает, что виртуальная функция не может быть переопределена в производном классе или что класс не может наследоваться.

Содержание

[править]Синтаксис

При применении к функции-элементу идентификатор final появляется сразу после декларатора в синтаксисе объявления функции-элемента или определения функции-элемента внутри определения класса.

Применительно к классу идентификатор final появляется в начале определения класса, сразу после имени класса.

деклараторпоследовательность-спецификаторов-виртуальности (необязательно)чистый-спецификатор (необязательно) (1)
деклараторпоследовательность-спецификаторов-виртуальности (необязательно)тело-функции (2)
ключевое-слово-классаатрибуты (необязательно)имя-заголовка-классаспецификатор-виртуальности-класса (необязательно)предложение-базы (необязательно) (3)
1) В объявлении функции-элемента final может появиться в последовательности-спецификаторов-виртуальности сразу после декларатора и перед чистым-спецификатором, если используется.
2) В определении функции-элемента внутри определения класса final может появиться в последовательности-спецификаторов-виртуальности сразу после декларатора и непосредственно перед телом-функции.
3) В определении класса 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) явно объявляет, что метод переопределяет другой метод [править]
close