10 December 2022

C++ 核心指南目录

C.128: Virtual functions should specify exactly one of virtual, override, or final

理由

更好的可读性。更快的检测到错误。明确指定是virtual, overridefinal, 可以更清楚的说明代码意图,让编译器捕捉到基类和继承类之间的类型不匹配错误。然而,添加两个以上这三个关键字就多余了,也容易导致错误。

简单的说:

  • 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 的时候,不管你把一个虚函数设置为 overridefinal 无关紧要了。

注意

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

强化

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