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

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