Classes and class hierarchies
C.128
Virtual functions should specify exactly one of `virtual`, `override`, or `final`
Reason
Readability. Detection of mistakes. Writing explicit virtual, override, or final is self-documenting and enables the compiler to catch mismatch of types and/or names between base and derived classes. However, writing more than one of these three is both redundant and a potential source of errors.
It's simple and clear:
virtualmeans exactly and only "this is a new virtual function."overridemeans exactly and only "this is a non-final overrider."finalmeans exactly and only "this is a final overrider."
Example, bad
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()
// ...
};
Example, good
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()
// ...
};
Discussion
We want to eliminate two particular classes of errors:
- implicit virtual: the programmer intended the function to be implicitly virtual and it is (but readers of the code can't tell); or the programmer intended the function to be implicitly virtual but it isn't (e.g., because of a subtle parameter list mismatch); or the programmer did not intend the function to be virtual but it is (because it happens to have the same signature as a virtual in the base class)
- implicit override: the programmer intended the function to be implicitly an overrider and it is (but readers of the code can't tell); or the programmer intended the function to be implicitly an overrider but it isn't (e.g., because of a subtle parameter list mismatch); or the programmer did not intend the function to be an overrider but it is (because it happens to have the same signature as a virtual in the base class -- note this problem arises whether or not the function is explicitly declared virtual, because the programmer might have intended to create either a new virtual function or a new non-virtual function)
Note: On a class defined as final, each individual virtual function should use either override or final; there is no semantic difference in this case.
Note: Use final on functions sparingly. It does not necessarily lead to optimization, and it precludes further overriding.
Enforcement
- Compare virtual function names in base and derived classes and flag uses of the same name that do not override.
- Flag overrides with neither
overridenorfinal. - Flag function declarations that use more than one of
virtual,override, andfinal.