final
specifier
(since C++11)
Spécifie qu'une fonction virtuelle ne peut pas être redéfinie dans une classe dérivée, ou qu'une classe ne peut pas être dérivée .
Table des matières |
Syntaxe
Lorsqu'il est appliqué à une fonction membre, l'identificateur
final
apparaît immédiatement après le
déclarateur
dans la syntaxe d'une déclaration de fonction membre ou d'une définition de fonction membre à l'intérieur d'une définition de classe.
Lorsqu'il est appliqué à une classe (y compris struct et union), l'identifiant
final
apparaît au début de la définition de la classe, immédiatement après le nom de la classe, et ne peut pas apparaître dans une déclaration de classe.
| declarator virt-specifier-seq (optionnel) pure-specifier (optionnel) | (1) | ||||||||
| declarator virt-specifier-seq (optionnel) function-body | (2) | ||||||||
| class-key attr (optionnel) class-head-name class-virt-specifier (optionnel) base-clause (optionnel) | (3) | (jusqu'en C++26) | |||||||
| class-key attr (optionnel) class-head-name class-prop-specifier-seq (optionnel) base-clause (optionnel) | (4) | (depuis C++26) | |||||||
final
peut apparaître dans
virt-specifier-seq
immédiatement après le déclarateur, et avant le
pure-specifier
, si utilisé.
final
peut apparaître dans
virt-specifier-seq
immédiatement après le déclarateur et juste avant
function-body
.
final
peut apparaître comme
class-virt-specifier
immédiatement après le nom de la classe, juste avant les deux-points qui commencent la
base-clause
, si elle est utilisée.
final
peut apparaître dans
class-prop-specifier-seq
, si utilisé, mais seulement une fois.
Dans les cas
(1,2)
,
virt-specifier-seq
, si utilisé, est soit
override
soit
final
, soit
final override
ou
override final
. Dans le cas
(3)
, la seule valeur autorisée de
class-virt-specifier
, si utilisé, est
final
. Dans le cas
(4)
, la
class-prop-specifier-seq
, si utilisée, peut contenir n'importe quel nombre de
spécificateurs de propriété de classe
(depuis C++26)
, mais chacun ne peut apparaître qu'au maximum une fois.
Explication
Lorsqu'il est utilisé dans une déclaration ou une définition de fonction virtuelle, final spécifie que la fonction est virtuelle et garantit qu'elle ne peut pas être redéfinie par les classes dérivées. Le programme est mal formé (une erreur de compilation est générée) dans le cas contraire.
Lorsqu'il est utilisé dans une définition de classe, final spécifie que cette classe ne peut pas apparaître dans la base-specifier-list d'une autre définition de classe (en d'autres termes, ne peut pas être dérivée). Le programme est mal formé dans le cas contraire (une erreur de compilation est générée). final peut également être utilisé avec une union , auquel cas il n'a aucun effet (autre que sur le résultat de std::is_final ) (depuis C++14) , car les unions ne peuvent pas être dérivées.
final est un identifiant ayant une signification particulière lorsqu'il est utilisé dans une déclaration de fonction membre ou un en-tête de classe. Dans d'autres contextes, il n'est pas réservé et peut être utilisé pour nommer des objets et des fonctions.
Remarque
Dans une séquence des jetons suivants :
- l'un des mots-clés class , struct et union
- un identifiant éventuellement qualifié
- final
- l'un des symboles : et {
le troisième jeton final dans la séquence est toujours considéré comme un spécificateur plutôt qu'un identifiant.
struct A; struct A final {}; // OK, définition de struct A, // pas d'initialisation de valeur de variable final struct X { struct C { constexpr operator int() { return 5; } }; struct B final : C{}; // OK, définition de classe imbriquée B, // pas déclaration d'un membre champ de bits final }; // Utilisation anormale de final. struct final final // OK, définition d'une struct nommée `final` dont { // on ne peut pas hériter }; // struct final final {}; // Erreur: redéfinition de `struct final`, PAS une // définition d'une variable `final` utilisant un // spécificateur de type élaboré `struct final` suivi // d'une initialisation d'agrégat // struct override : final {}; // Erreur: ne peut pas dériver du type de base final; // `override` dans ce contexte est un nom normal void foo() { [[maybe_unused]] final final; // OK, déclaration d'une variable nommée `final` de type // `struct final` } struct final final; // OK, déclaration d'une variable nommée `final` de type // `struct final` utilisant un spécificateur de type élaboré int main() { }
Mots-clés
Exemple
struct Base { virtual void foo(); }; struct A : Base { void foo() final; // Base::foo est surchargée et A::foo est la surcharge finale void bar() final; // Erreur : bar ne peut pas être final car elle n'est pas virtuelle }; struct B final : A // struct B est final { void foo() override; // Erreur : foo ne peut pas être surchargée car elle est final dans A }; struct C : B {}; // Erreur : B est final
Sortie possible :
main.cpp:9:10: error: 'void A::bar()' marked 'final', but is not virtual
9 | void bar() final; // Erreur : bar ne peut pas être final car elle n'est pas virtuelle
| ^~~
main.cpp:14:10: error: virtual function 'virtual void B::foo()' overriding final function
14 | void foo() override; // Erreur : foo ne peut pas être surchargée car elle est final dans A
| ^~~
main.cpp:8:10: note: overridden function is 'virtual void A::foo()'
8 | void foo() final; // Base::foo est surchargée et A::foo est la surcharge finale
| ^~~
main.cpp:17:8: error: cannot derive from 'final' base 'B' in derived type 'C'
17 | struct C : B // Erreur : B est final
|
Références
- Norme C++23 (ISO/CEI 14882:2024) :
-
- 11 Classes [class]
-
- 11.7.3 Fonctions virtuelles [class.virtual]
- Norme C++20 (ISO/CEI 14882:2020) :
-
- 11 Classes [class]
-
- 11.7.2 Fonctions virtuelles [class.virtual]
- Norme C++17 (ISO/IEC 14882:2017) :
-
- 12 Classes [class]
-
- 13.3 Fonctions virtuelles [class.virtual]
- Norme C++14 (ISO/CEI 14882:2014) :
-
- 9 Classes [class]
-
- 10.3 Fonctions virtuelles [class.virtual]
- Norme C++11 (ISO/IEC 14882:2011) :
-
- 9 Classes [class]
-
- 10.3 Fonctions virtuelles [class.virtual]
Rapports de défauts
Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.
| DR | Appliqué à | Comportement tel que publié | Comportement corrigé |
|---|---|---|---|
| CWG 1318 | C++11 |
une définition de classe qui a
final
après le nom de la classe et une
liste de spécification de membres vide pourrait faire de final un identifiant |
final
est toujours un
spécificateur dans ce cas |
Voir aussi
override
spécificateur
(C++11)
|
déclare explicitement qu'une méthode remplace une autre méthode |
| spécificateurs de propriété de classe (C++26) | final spécificateur (C++11) , remplaçabilité (C++26) , relocalisabilité triviale (C++26) |