10 December 2022

C++ 核心指南目录

“Virtual functions should specify exactly one of virtual, override, or final”

理由

更好的可读性。更快的检测到错误。明确指定是 virtual, override 或 final,使得代码说明更清楚,让编译器捕捉类型错误:是基类还是继承类。然而,添加两个以上这三个关键字就多余了,也容易导致错误。

更简单更清晰。

  • virtual 只意味着“这是一个新的虚函数”
  • override 只意味着“这是不是一个 final 的重载”
  • final 只意味着“这是一个 final 的重载”

坏例子

struct B {
    void f1(int);
    virtual void f2(int) const;
    virtual void f3(int);
    // ...
};

struct D : B {
    void f1(int);        // bad (hope for a warning): D::f1() hides B::f1()
    void f2(int) const;  // bad (but conventional and valid): no explicit override
    void f3(double);     // bad (hope for a warning): D::f3() hides B::f3()
    // ...
};

好例子

struct Better : B { void f1(int) override; // error (caught):
    Better::f1() hides B::f1() void f2(int) const override; void
    f3(double) override; // error (caught): Better::f3() hides B::f3()
    // ...  };

讨论

我们想避免某些类型的错误:

  • 隐式的虚函数:程序员想设计一个函数为隐式的虚函数,事实上也是虚函数(但是读代码的人分辩不出来);或者程序员计划设计一个隐式的虚函数,但是其实上不是虚函数(比如因为某些席位的参数列表不匹配);或者程序员不想把一个函数设计成虚函数,但是其实上是虚函数(因为该函数刚好和基类的虚函数签名一致)。
  • 隐式的重载:程序员计划设计一个函数是重载函数,事实上也是一个重载函数(但是读代码的人看不出来);或者程序员计划设计一个函数为重载函数,但是其实上不是(比如,因为某些细微的参数列表不匹配);或者程序员不想把一个函数设计成重载函数,但是其实上是一个重载(因为刚好该函数与基类的虚函数签名一致,注意,不论该函数是声明为虚函数还是非虚函数,这个问题都可能出现。因为程序员可能计划创建一个新的虚函数或者一个新的非虚函数)。

注意

当一个类被声明为 final 的时候,不管你把一个虚函数设置为 override 或 final 无关紧要了。

注意

减少使用 final 函数,因为不会使得代码更优化,只是防止被重载。

强化

  • 比较基类和派生类中的虚函数名字,标记用了同一个名字,却不是重载的情况
  • 标记没有用 override 或 final 的重载函数
  • 标记使用了一个以上 virtual、override 和 final 的函数声明