Namespaces
Variants

final specifier (since C++11)

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Virtual function
override specifier (C++11)
final specifier (C++11)
Special member functions
Templates
Miscellaneous

Spezifiziert, dass eine virtual function nicht in einer abgeleiteten Klasse überschrieben werden kann, oder dass eine Klasse nicht derived from werden kann.

Inhaltsverzeichnis

Syntax

Wenn auf eine Memberfunktion angewendet wird, erscheint der Bezeichner final unmittelbar nach dem Deklarator in der Syntax einer Memberfunktionsdeklaration oder einer Memberfunktionsdefinition innerhalb einer Klassendefinition.

Wenn auf eine Klasse (einschließlich struct und union) angewendet, erscheint der Bezeichner final am Anfang der Klassendefinition, unmittelbar nach dem Namen der Klasse, und kann nicht in einer Klassendeklaration erscheinen.

Deklarator virt-specifier-seq  (optional) pure-specifier  (optional) (1)
Deklarator virt-specifier-seq  (optional) Funktionskörper (2)
Klassen-Schlüssel attr  (optional) Klassenkopfname class-virt-specifier  (optional) Basisklausel  (optional) (3) (bis C++26)
Klassen-Schlüssel attr  (optional) Klassenkopfname class-prop-specifier-seq  (optional) Basisklausel  (optional) (4) (seit C++26)
1) In einer Member-Funktionsdeklaration darf final in der virt-specifier-seq unmittelbar nach dem Deklarator und vor dem pure-specifier erscheinen, falls verwendet.
2) In einer Memberfunktionsdefinition innerhalb einer Klassendefinition, final kann in virt-specifier-seq unmittelbar nach dem Deklarator und direkt vor function-body erscheinen.
3) In einer Klassendefinition kann final als class-virt-specifier unmittelbar nach dem Klassennamen erscheinen, direkt vor dem Doppelpunkt, der den base-clause einleitet, falls verwendet.
4) In einer Klassendefinition darf final in der class-prop-specifier-seq erscheinen, falls verwendet, jedoch nur einmal.

In den Fällen (1,2) ist die virt-specifier-seq , falls verwendet, entweder override oder final , oder final override oder override final . Im Fall (3) ist der einzige zulässige Wert von class-virt-specifier , falls verwendet, final . Im Fall (4) kann die class-prop-specifier-seq , falls verwendet, beliebig viele class property specifiers enthalten (seit C++26) , aber jeder darf höchstens einmal vorkommen.

Erklärung

Wenn es in einer Deklaration oder Definition einer virtuellen Funktion verwendet wird, final Spezifizierer stellt sicher, dass die Funktion virtuell ist und spezifiziert, dass sie von abgeleiteten Klassen nicht überschrieben werden darf. Andernfalls ist das Programm fehlerhaft (es wird ein Kompilierzeitfehler generiert).

Wenn in einer Klassendefinition verwendet, final spezifiziert, dass diese Klasse nicht in der base-specifier-list einer anderen Klassendefinition erscheinen darf (mit anderen Worten, sie kann nicht abgeleitet werden). Andernfalls ist das Programm fehlerhaft (es wird ein Compile-Time-Fehler generiert). final kann auch mit einer union -Definition verwendet werden, in welchem Fall es keine Auswirkung hat (außer auf das Ergebnis von std::is_final ) (seit C++14) , da Unions nicht abgeleitet werden können.

final ist ein Bezeichner mit einer besonderen Bedeutung, wenn er in einer Member-Funktionsdeklaration oder einem Klassenkopf verwendet wird. In anderen Kontexten ist er nicht reserviert und kann zur Benennung von Objekten und Funktionen verwendet werden.

Hinweis

In einer Folge der folgenden Tokens:

  1. einer von class , struct und union
  2. ein möglicherweise qualifizierter Bezeichner
  3. final
  4. einer von : und {

das dritte Token final in der Sequenz wird immer als Spezifizierer anstelle eines Identifikators betrachtet.

struct A;
struct A final {}; // OK, Definition von struct A,
                   // keine Wertinitialisierung der Variable final
struct X
{
    struct C { constexpr operator int() { return 5; } };
    struct B final : C{}; // OK, Definition der geschachtelten Klasse B,
                          // keine Deklaration eines Bitfeld-Members final
};
// Ungewöhnliche final-Verwendung.
struct final final // OK, Definition einer struct namens `final`, von der
{                  // man nicht erben kann
};
// struct final final {}; // Fehler: Neudefinition von `struct final`, KEINE
                          // Definition einer Variable `final` mit einem erweiterten
                          // Typspezifizierer `struct final` gefolgt von einer
                          // Aggregatinitialisierung
// struct override : final {}; // Fehler: Kann nicht von finaler Basisklasse ableiten;
                               // `override` ist in diesem Kontext ein normaler Name
void foo()
{
    [[maybe_unused]]
    final final; // OK, Deklaration einer Variable namens `final` vom Typ
                 // `struct final` 
}
struct final final; // OK, Deklaration einer Variable namens `final` vom Typ
                    // `struct final` mit einem erweiterten Typspezifizierer
int main()
{
}

Schlüsselwörter

final

Beispiel

struct Base
{
    virtual void foo();
};
struct A : Base
{
    void foo() final; // Base::foo wird überschrieben und A::foo ist der finale Override
    void bar() final; // Fehler: bar kann nicht final sein, da es nicht virtuell ist
};
struct B final : A // struct B ist final
{
    void foo() override; // Fehler: foo kann nicht überschrieben werden, da es in A final ist
};
struct C : B {}; // Fehler: B ist final

Mögliche Ausgabe:

main.cpp:9:10: error: 'void A::bar()' marked 'final', but is not virtual
    9 |     void bar() final; // Fehler: bar kann nicht final sein, da es nicht virtuell ist
      |          ^~~
main.cpp:14:10: error: virtual function 'virtual void B::foo()' overriding final function
   14 |     void foo() override; // Fehler: foo kann nicht überschrieben werden, da es in A final ist
      |          ^~~
main.cpp:8:10: note: overridden function is 'virtual void A::foo()'
    8 |     void foo() final; // Base::foo wird überschrieben und A::foo ist der finale Override
      |          ^~~
main.cpp:17:8: error: cannot derive from 'final' base 'B' in derived type 'C'
   17 | struct C : B // Fehler: B ist final
      |

Referenzen

  • C++23-Standard (ISO/IEC 14882:2024):
  • 11 Klassen [class]
  • 11.7.3 Virtuelle Funktionen [class.virtual]
  • C++20-Standard (ISO/IEC 14882:2020):
  • 11 Klassen [class]
  • 11.7.2 Virtuelle Funktionen [class.virtual]
  • C++17-Standard (ISO/IEC 14882:2017):
  • 12 Klassen [class]
  • 13.3 Virtuelle Funktionen [class.virtual]
  • C++14-Standard (ISO/IEC 14882:2014):
  • 9 Klassen [class]
  • 10.3 Virtuelle Funktionen [class.virtual]
  • C++11-Standard (ISO/IEC 14882:2011):
  • 9 Klassen [class]
  • 10.3 Virtuelle Funktionen [class.virtual]

Fehlerberichte

Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.

DR Angewendet auf Verhalten wie veröffentlicht Korrektes Verhalten
CWG 1318 C++11 eine Klassendefinition, die final nach dem Klassennamen und eine
leere Mitgliederspezifikationsliste hat, könnte final zu einem Bezeichner machen
final ist in diesem Fall immer ein
Spezifizierer

Siehe auch

override Spezifizierer (C++11) deklariert explizit, dass eine Methode eine andere Methode überschreibt
Klassen-Eigenschafts-Spezifizierer (C++26) final Spezifizierer (C++11) , Ersetzbarkeit (C++26) , triviale Relokalisierbarkeit (C++26)