final 说明符 (C++11 起)
来自cppreference.com
语法
当应用到成员函数时,标识符 final
在类定义中的成员函数声明或成员函数定义的语法中,紧随声明符之后出现。
当应用到类(包括结构体和联合体)时,标识符 final
在类定义的开头,紧跟类名之后出现,但不能在类声明中出现。
声明符 虚说明符序列 (可选) 纯说明符 (可选) | (1) | ||||||||
声明符 虚说明符序列 (可选) 函数体 | (2) | ||||||||
类关键词 属性 (可选) 类头名 类虚说明符 (可选) 基类子句 (可选) | (3) | ||||||||
2) 在类定义内的成员函数定义中,
final
可以在紧跟声明符之后并紧接 函数体 之前的 虚说明符序列 中出现。3) 在类定义中,
final
可以在紧跟类名之后,紧接 基类子句(如果使用它)起头的冒号之前,作为 类虚说明符 出现。情况 (1,2) 中,如果有使用 虚说明符序列,那么它是 override
、final
、final override
或 override final
之一。情况 (3) 中,如果有使用 类虚说明符 则只允许 final
。
解释
当在虚函数声明或定义中使用时,final 说明符确保函数为虚并指定它不能被派生类覆盖,否则程序非良构(生成编译时错误)。
当在类定义中使用时,final 指定此类不能在另一类的定义中的 基类说明符列表 中出现(换言之,不能派生于它),否则程序非良构(生成编译时错误)。final 也可以用于联合体定义,此时它没有效果(除了 std::is_final 的输出结果) (C++14 起),因为不能从联合体派生。
final 是在成员函数声明或类头部中使用时有特殊含义的标识符。其他语境中它并未被保留,而且可用于命名对象或函数。
注解
在由以下记号组成的序列中:
- class,struct 和 union 之一
- 可有限定的标识符
- final
- : 或 {
序列中的第三个记号 final 只会被视为说明符而不是标识符。
运行此代码
struct A; struct A final {}; // OK:结构体 A 的定义,而不是变量 final 的值初始化 struct X { struct C { constexpr operator int() { return 5; } }; struct B final : C{}; // OK:嵌套类 B 的定义,而不是位域成员 final 的声明 }; // 不正常的 final 用法。 struct final final // OK,名为 final 的结构体的定义,不能继承 { }; // struct final final {}; // 错误:struct final 的重复定义, // *并非* 使用详述类型说明符 `struct final` 跟着一个聚合体初始化 // 的变量 final 的定义 // struct override : final {}; // 错误:不能从 final 基类型派生; // 给定语境中的 override 是正常的名字 void foo() { [[maybe_unused]] final final; // OK,struct final 类型的名为 final 的变量的声明 } struct final final; // OK,struct final 类型的名为 final 的变量的声明 // 使用详述类型说明符 int main() { }
关键词
示例
运行此代码
struct Base { virtual void foo(); }; struct A : Base { void foo() final; // Base::foo 被覆盖而 A::foo 是最终覆盖函数 void bar() final; // 错误:bar 非虚,因此它不能是 final 的 }; struct B final : A // struct B 为 final { void foo() override; // 错误:foo 不能被覆盖,因为它在 A 中是 final 的 }; struct C : B {}; // 错误:B 是 final 的
可能的输出:
main.cpp:9:10: 错误:'void A::bar()' 标记为 'final',但不是虚函数 9 | void bar() final; // 错误:bar 非虚,因此它不能是 final 的 | ^~~ main.cpp:14:10: 错误:虚函数 'virtual void B::foo()' 覆盖 final 函数 14 | void foo() override; // 错误:foo 不能被覆盖,因为它在 A 中是 final 的 | ^~~ main.cpp:8:10: 注意:函数 'virtual void A::foo()' 被覆盖 8 | void foo() final; // Base::foo 被覆盖而 A::foo 是最终覆盖函数 | ^~~ main.cpp:17:8: 错误:不能在派生类型 'C' 中派生自 'final' 基类 'B' 17 | struct C : B // 错误:B 是 final 的 |
引用
- C++23 标准(ISO/IEC 14882:2024):
- 11 Classes [class]
- 11.7.3 Virtual functions [class.virtual]
- C++20 标准(ISO/IEC 14882:2020):
- 11 Classes [class]
- 11.7.2 Virtual functions [class.virtual]
- C++17 标准(ISO/IEC 14882:2017):
- 12 Classes [class]
- 13.3 Virtual functions [class.virtual]
- C++14 标准(ISO/IEC 14882:2014):
- 9 Classes [class]
- 10.3 Virtual functions [class.virtual]
- C++11 标准(ISO/IEC 14882:2011):
- 9 Classes [class]
- 10.3 Virtual functions [class.virtual]
缺陷报告
下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。
缺陷报告 | 应用于 | 出版时的行为 | 正确行为 |
---|---|---|---|
CWG 1318 | C++11 | 成员说明列表为空且类名后有 final 的类定义可能会将 final 作为标识符 | 此时 final 只能是说明符 |
参阅
override 说明符(C++11)
|
显式说明方法覆盖另一方法 |