final 说明符 (C++11 起)

来自cppreference.com
< cpp‎ | language

指定某个虚函数不能在派生类中被覆盖,或者某个类不能被派生

语法

当应用到成员函数时,标识符 final 在类定义中的成员函数声明或成员函数定义的语法中,紧随声明符之后出现。

当应用到类时,标识符 final 在类定义的开头,紧跟类名之后出现。

声明符 虚说明符序列(可选) 纯说明符(可选) (1)
声明符 虚说明符序列(可选) 函数体 (2)
类关键词 attr(可选) 类头名 类虚说明符(可选) 基类子句(可选) (3)
1) 在成员函数声明中,final 可以在紧跟声明符之后的 虚说明符序列 中出现,如果有使用 纯说明符 则在其之前。
2) 在类定义内的成员函数定义中,final 可以在紧跟声明符之后并紧接 函数体 之前的 虚说明符序列 中出现。
3) 在类定义中,final 可以在紧跟类名之后,紧接 基类子句(若使用它)起头的冒号之前,作为 类虚说明符 出现。

情况 (1,2) 中,如果有使用 虚说明符序列,那么它是 overridefinalfinal overrideoverride final 之一。情况 (3) 中,如果有使用 类虚说明符 则只允许 final

解释

当在虚函数声明或定义中使用时,final 说明符确保函数为虚并指定其不可被派生类覆盖,否则程序为谬构(生成编译时错误)。

当在类定义中使用时,final 指定此类不可在另一类的定义中的 基类说明符列表 中出现(换言之,不能派生于它),否则程序非良构(生成编译时错误)。final 也可以用于联合体定义,此时下它没有效果(除了 std::is_final 的输出结果) (C++14 起),因为不能从联合体派生。

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 的
      |

参阅

override 说明符(C++11) 显式说明方法覆盖另一方法