final 说明符 (C++11 起)

来自cppreference.com
< cpp‎ | language


 
 
C++ 语言
 
 

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

语法

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

当应用到类(包括结构体和联合体)时,标识符 final 在类定义的开头,紧跟类名之后出现,但不能在类声明中出现。

声明符 虚说明符序列 (可选) 纯说明符 (可选) (1)
声明符 虚说明符序列 (可选) 函数体 (2)
类关键词 属性 (可选) 类头名 类虚说明符 (可选) 基类子句 (可选) (3) (C++26 前)
类关键词 属性 (可选) 类头名 类性质说明符序列 (可选) 基类子句 (可选) (4) (C++26 起)
1) 在成员函数声明中,final 可以在紧跟声明符之后的虚说明符序列 中出现,如果有使用 纯说明符 那么应在它之前。
2) 在类定义内的成员函数定义中,final 可以在紧跟声明符之后并紧接函数体 之前的虚说明符序列 中出现。
3) 在类定义中,final 可以在紧跟类名之后,紧接基类子句(如果使用它)起头的冒号之前,作为类虚说明符 出现。
4) 在类定义中,final 可以在类性质说明符序列 中出现,但若使用则仅允许出现一次。

情况 (1,2) 中,如果有使用虚说明符序列,那么它是 override、final、final override 或 override final 之一。情况 (3) 中,如果有使用类虚说明符 则只允许 final。情况 (4) 中,如果有使用类性质说明符序列,则可有任意数量的类性质说明符 (C++26 起),但每个最多仅可出现一次。

解释

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

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

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

注解

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

  1. class,struct 和 union 之一
  2. 可有限定的标识符
  3. final
  4. : 或 {

序列中的第三个记号 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()
{
}

关键词

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++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) 显式声明一方法覆盖另一方法
类性质说明符 (C++26) final 说明符 (C++11)、可替换性 (C++26)、可平凡重定位性 (C++26)