Namensräume
Varianten
Aktionen

final-Spezifizierer (seit C++11)

Von cppreference.com
< cpp‎ | Sprache
 
 
C++ Sprache
Allgemeine Themen
Kontrollfluss
Bedingte Ausführungsaussagen
if
Iterationsanweisungen (Schleifen)
for
Bereichs-for (C++11)
Sprunganweisungen
Funktionen
Funktionsdeklaration
Lambda-Funktionsausdruck
inline-Spezifizierer
Dynamische Ausnahmespezifikationen (bis C++17*)
noexcept-Spezifizierer (C++11)
Ausnahmen
Namensräume
Typen
Spezifizierer
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Speicherdauer-Spezifizierer
Initialisierung
Ausdrücke
Alternative Darstellungen
Literale
Boolesch - Ganzzahl - Gleitkommazahl
Zeichen - String - nullptr (C++11)
Benutzerdefinierte (C++11)
Dienstprogramme
Attribute (C++11)
Typen
typedef-Deklaration
Typalias-Deklaration (C++11)
Umwandlungen
Speicherzuweisung
Klassen
Klassenspezifische Funktionseigenschaften
Virtuelle Funktion
override-Spezifizierer (C++11)  
final-Spezifizierer (C++11)
explicit (C++11)
static

Spezielle Member-Funktionen
Templates
Sonstiges
 
 

Gibt an, dass eine virtuelle Funktion in einer abgeleiteten Klasse nicht überschrieben werden kann oder dass von einer Klasse nicht abgeleitet werden kann.

Inhalt

[bearbeiten] Syntax

Wenn auf eine Memberfunktion angewendet, erscheint der Bezeichner final direkt 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, direkt 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) function-body (2)
class-key attr (optional) class-head-name class-virt-specifier (optional) base-clause (optional) (3) (bis C++26)
class-key attr (optional) class-head-name class-prop-specifier-seq (optional) base-clause (optional) (4) (seit C++26)
1) In einer Memberfunktionsdeklaration kann final im virt-specifier-seq unmittelbar nach dem Deklarator und vor dem pure-specifier, falls verwendet, stehen.
2) In einer Memberfunktionsdefinition innerhalb einer Klassendefinition kann final im virt-specifier-seq unmittelbar nach dem Deklarator und direkt vor function-body stehen.
3) In einer Klassendefinition kann final als class-virt-specifier unmittelbar nach dem Klassennamen und direkt vor dem Doppelpunkt stehen, der die base-clause einleitet, falls verwendet.
4) In einer Klassendefinition kann final im class-prop-specifier-seq, falls verwendet, vorkommen, aber nur einmal.

In den Fällen (1,2) ist virt-specifier-seq, falls verwendet, entweder override oder final, oder final override oder override final. Im Fall (3) ist der einzig erlaubte Wert von class-virt-specifier, falls verwendet, final. Im Fall (4) kann class-prop-specifier-seq, falls verwendet, eine beliebige Anzahl von Klasseneigenschaftsspezifizierern (seit C++26) haben, aber jeder kann höchstens einmal vorkommen.

[bearbeiten] Erklärung

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

Wenn der final-Spezifizierer in einer Klassendefinition verwendet wird, gibt er an, dass diese Klasse nicht in der base-specifier-list einer anderen Klassendefinition vorkommen darf (d. h. von ihr kann nicht abgeleitet werden). Andernfalls ist das Programm fehlerhaft (ein Kompilierungsfehler wird generiert). final kann auch mit einer union-Definition verwendet werden, in diesem Fall hat es keine Auswirkung (außer auf das Ergebnis von std::is_final)(seit C++14), da von Unions nicht abgeleitet werden kann.

final ist ein Bezeichner mit besonderer Bedeutung, wenn er in einer Memberfunktionsdeklaration oder einem Klassenheader verwendet wird. In anderen Kontexten ist er nicht reserviert und kann zur Benennung von Objekten und Funktionen verwendet werden.

[bearbeiten] Hinweis

In einer Sequenz der folgenden Tokens

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

wird das dritte Token final in der Sequenz immer als Spezifizierer und nicht als Bezeichner betrachtet.

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()
{
}

[bearbeiten] Schlüsselwörter

final

[bearbeiten] Beispiel

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

Mögliche Ausgabe

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
      |

[bearbeiten] 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]

[bearbeiten] Fehlerberichte

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

DR angewendet auf Verhalten wie veröffentlicht Korrigiertes Verhalten
CWG 1318 C++11 eine Klassendefinition, die final nach dem Klassennamen und einer
leeren Member-Spezifikationsliste hat, könnte final zu einem Bezeichner machen
final ist in diesem Fall immer ein
Spezifizierer

[bearbeiten] Siehe auch

override-Spezifizierer (C++11) deklariert explizit, dass eine Methode eine andere Methode überschreibt[bearbeiten]
Klasseneigenschaftsspezifizierer (C++26) final-Spezifizierer (C++11), Ersetzbarkeit (C++26), Triviale Relokationsfähigkeit (C++26)[bearbeiten]