Difference between revisions of "cpp/language/final"
m (Text replace - "{{source cpp" to "{{source") |
m (→Keywords: correct type) |
||
(48 intermediate revisions by 24 users not shown) | |||
Line 1: | Line 1: | ||
− | {{title|final specifier}} | + | {{title|{{tt|final}} specifier {{mark since c++11}}}} |
− | {{cpp/language/ | + | {{cpp/language/classes/navbar}} |
− | Specifies that a | + | Specifies that a {{rlp|virtual|virtual function}} cannot be overridden in a derived class, or that a class cannot be {{rlp|derived class|derived from}}. |
===Syntax=== | ===Syntax=== | ||
− | {{ | + | When applied to a member function, the identifier {{tt|final}} appears immediately after the {{rlp|function|declarator}} in the syntax of a member function declaration or a member function definition inside a class definition. |
− | {{ | + | |
− | {{ | + | When applied to a class (including struct and union), the identifier {{tt|final}} appears at the beginning of the class definition, immediately after the name of the class, and cannot appear in a class declaration. |
− | {{ | + | |
+ | {{sdsc begin}} | ||
+ | {{sdsc|num=1|{{spar|declarator}} {{spar optional|virt-specifier-seq}} {{spar optional|pure-specifier}}}} | ||
+ | {{sdsc|num=2|{{spar|declarator}} {{spar optional|virt-specifier-seq}} {{spar|function-body}}}} | ||
+ | {{sdsc|num=3|{{spar|class-key}} {{spar optional|attr}} {{spar|class-head-name}} {{spar optional|class-virt-specifier}} {{spar optional|base-clause}}}} | ||
+ | {{sdsc end}} | ||
+ | @1@ In a member function declaration, {{tt|final}} may appear in {{spar|virt-specifier-seq}} immediately after the declarator, and before the {{rlp|abstract class|{{spar|pure-specifier}}}}, if used. | ||
+ | @2@ In a member function definition inside a class definition, {{tt|final}} may appear in {{spar|virt-specifier-seq}} immediately after the declarator and just before {{spar|function-body}}. | ||
+ | @3@ In a class definition, {{tt|final}} may appear as {{spar|class-virt-specifier}} immediately after the name of the class, just before the colon that begins the {{spar|base-clause}}, if used. | ||
+ | |||
+ | In the cases {{v|1,2}}, {{spar|virt-specifier-seq}}, if used, is either {{rlpt|override}} or {{tt|final}}, or {{tt|final override}} or {{tt|override final}}. In the case {{v|3}}, the only allowed value of {{spar|class-virt-specifier}}, if used, is {{tt|final}}. | ||
− | |||
===Explanation=== | ===Explanation=== | ||
− | + | When used in a virtual function declaration or definition, {{c/core|final}} specifier ensures that the function is virtual and specifies that it may not be overridden by derived classes. The program is ill-formed (a compile-time error is generated) otherwise. | |
− | {{ | + | When used in a class definition, {{c/core|final}} specifies that this class may not appear in the {{spar|base-specifier-list}} of another class definition (in other words, cannot be derived from). The program is ill-formed otherwise (a compile-time error is generated). {{c/core|final}} can also be used with a {{rlp|union}} definition, in which case it has no effect{{rev inl|since=c++14| (other than on the outcome of {{lc|std::is_final}})}}, since unions cannot be derived from. |
+ | |||
+ | {{c/core|final}} is an identifier with a special meaning when used in a member function declaration or class head. In other contexts, it is not reserved and may be used to name objects and functions. | ||
+ | |||
+ | ===Note=== | ||
+ | In a sequence of the following tokens: | ||
+ | # one of {{c/core|class}}, {{c/core|struct}} and {{c/core|union}} | ||
+ | # a possibly qualified {{rlp|identifiers|identifier}} | ||
+ | # {{c/core|final}} | ||
+ | # one of {{c|:}} and {{c|{}} | ||
+ | the third token {{c/core|final}} in the sequence is always considered as a specifier instead of an identifier. | ||
+ | {{example | ||
+ | |code= | ||
+ | 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() | ||
+ | { | ||
+ | } | ||
+ | }} | ||
+ | |||
+ | ===Keywords=== | ||
+ | {{ltt|cpp/identifier_with_special_meaning/final}} | ||
===Example=== | ===Example=== | ||
− | {{ | + | {{example |
− | struct | + | |code= |
+ | struct Base | ||
{ | { | ||
− | virtual void foo() | + | virtual void foo(); |
}; | }; | ||
− | struct | + | struct A : Base |
{ | { | ||
− | void foo(); // | + | 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 | + | 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 | ||
+ | |p=true | ||
+ | |output= | ||
+ | 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 | ||
+ | {{!}} | ||
}} | }} | ||
+ | |||
+ | ===References=== | ||
+ | {{ref std c++23}} | ||
+ | {{ref std|section=11|title=Classes|id=class}} | ||
+ | {{ref std|section=11.7.3|title=Virtual functions|id=class.virtual}} | ||
+ | {{ref std end}} | ||
+ | {{ref std c++20}} | ||
+ | {{ref std|section=11|title=Classes|id=class}} | ||
+ | {{ref std|section=11.7.2|title=Virtual functions|id=class.virtual}} | ||
+ | {{ref std end}} | ||
+ | {{ref std c++17}} | ||
+ | {{ref std|section=12|title=Classes|id=class}} | ||
+ | {{ref std|section=13.3|title=Virtual functions|id=class.virtual}} | ||
+ | {{ref std end}} | ||
+ | {{ref std c++14}} | ||
+ | {{ref std|section=9|title=Classes|id=class}} | ||
+ | {{ref std|section=10.3|title=Virtual functions|id=class.virtual}} | ||
+ | {{ref std end}} | ||
+ | {{ref std c++11}} | ||
+ | {{ref std|section=9|title=Classes|id=class}} | ||
+ | {{ref std|section=10.3|title=Virtual functions|id=class.virtual}} | ||
+ | {{ref std end}} | ||
+ | |||
+ | ===Defect reports=== | ||
+ | {{dr list begin}} | ||
+ | {{dr list item|wg=cwg|dr=1318|std=C++11|before=a class definition which has {{c/core|final}} after the class name and an<br>empty member specification list might make {{c/core|final}} an identifier|after={{c|final}} is always a<br>specifier in this case}} | ||
+ | {{dr list end}} | ||
+ | |||
===See also=== | ===See also=== | ||
− | + | {{dsc begin}} | |
+ | {{dsc inc|cpp/language/dsc override}} | ||
+ | {{dsc end}} | ||
+ | |||
+ | {{langlinks|de|es|fr|it|ja|pt|ru|zh}} |
Latest revision as of 11:08, 13 September 2024
Specifies that a virtual function cannot be overridden in a derived class, or that a class cannot be derived from.
Contents |
[edit] Syntax
When applied to a member function, the identifier final
appears immediately after the declarator in the syntax of a member function declaration or a member function definition inside a class definition.
When applied to a class (including struct and union), the identifier final
appears at the beginning of the class definition, immediately after the name of the class, and cannot appear in a class declaration.
declarator virt-specifier-seq (optional) pure-specifier (optional) | (1) | ||||||||
declarator virt-specifier-seq (optional) function-body | (2) | ||||||||
class-key attr (optional) class-head-name class-virt-specifier (optional) base-clause (optional) | (3) | ||||||||
final
may appear in virt-specifier-seq immediately after the declarator, and before the pure-specifier, if used.final
may appear in virt-specifier-seq immediately after the declarator and just before function-body.final
may appear as class-virt-specifier immediately after the name of the class, just before the colon that begins the base-clause, if used.In the cases (1,2), virt-specifier-seq, if used, is either override
or final
, or final override
or override final
. In the case (3), the only allowed value of class-virt-specifier, if used, is final
.
[edit] Explanation
When used in a virtual function declaration or definition, final specifier ensures that the function is virtual and specifies that it may not be overridden by derived classes. The program is ill-formed (a compile-time error is generated) otherwise.
When used in a class definition, final specifies that this class may not appear in the base-specifier-list of another class definition (in other words, cannot be derived from). The program is ill-formed otherwise (a compile-time error is generated). final can also be used with a union definition, in which case it has no effect (other than on the outcome of std::is_final)(since C++14), since unions cannot be derived from.
final is an identifier with a special meaning when used in a member function declaration or class head. In other contexts, it is not reserved and may be used to name objects and functions.
[edit] Note
In a sequence of the following tokens:
- one of class, struct and union
- a possibly qualified identifier
- final
- one of : and {
the third token final in the sequence is always considered as a specifier instead of an identifier.
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() { }
[edit] Keywords
[edit] Example
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
Possible output:
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 |
[edit] References
- C++23 standard (ISO/IEC 14882:2024):
- 11 Classes [class]
- 11.7.3 Virtual functions [class.virtual]
- C++20 standard (ISO/IEC 14882:2020):
- 11 Classes [class]
- 11.7.2 Virtual functions [class.virtual]
- C++17 standard (ISO/IEC 14882:2017):
- 12 Classes [class]
- 13.3 Virtual functions [class.virtual]
- C++14 standard (ISO/IEC 14882:2014):
- 9 Classes [class]
- 10.3 Virtual functions [class.virtual]
- C++11 standard (ISO/IEC 14882:2011):
- 9 Classes [class]
- 10.3 Virtual functions [class.virtual]
[edit] Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 1318 | C++11 | a class definition which has final after the class name and an empty member specification list might make final an identifier |
final is always a specifier in this case |
[edit] See also
override specifier(C++11)
|
explicitly declares that a method overrides another method |