final 说明符 (C++11 起)
来自cppreference.com
语法
当应用到成员函数时,标识符 final
在类定义中的成员函数声明或成员函数定义的语法中,紧随声明符之后出现。
当应用到类时,标识符 final
在类定义的开头,紧跟类名之后出现。
声明符 虚说明符序列(可选) 纯说明符(可选) | (1) | ||||||||
声明符 虚说明符序列(可选) 函数体 | (2) | ||||||||
类关键词 attr(可选) 类头名 类虚说明符(可选) 基类子句(可选) | (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 };
示例
运行此代码
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++ 标准。
缺陷报告 | 应用于 | 出版时的行为 | 正确行为 |
---|---|---|---|
CWG 1318 | C++11 | 成员说明列表为空且类名后有 final 的类定义可能会将 final 作为标识符 | 此时 final 只能是说明符 |
参阅
override 说明符(C++11)
|
显式说明方法覆盖另一方法 |