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 是在成员函数声明或类头部中使用时有特殊含义的标识符。其他语境中它未被保留,而且可用于命名对象或函数。

注意

在由以下记号组成的序列中:

  • classstructunion 之一;
  • 可有限定的标识符
  • 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) 显式说明方法覆盖另一方法