Spec-Zone.ru › C++

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)
1) В объявлении функции-члена final может находиться в virt-specifier-seq непосредственно после декларатора и перед pure-specifier, если он используется.
2) В определении функции-члена внутри определения класса final может находиться в virt-specifier-seq непосредственно после декларатора и прямо перед function-body.
3) В определении класса 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 — это идентификатор, имеющий специальное значение при использовании в объявлении функции-члена или заголовке класса. В других контекстах он не зарезервирован и может использоваться для именования объектов и функций.

Примечание

В последовательности следующих токенов:

  1. один из class, struct и union
  2. возможно, квалифицированный идентификатор
  3. final
  4. один из : и {

третий токен 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()
{
}

Ключевые слова

final

Пример

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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API