final
and override
SpecifiersAs we’ll see in §15.6 (p. 620), it is legal for a derived class to define a function with the same name as a virtual in its base class but with a different parameter list. The compiler considers such a function to be independent from the base-class function. In such cases, the derived version does not override the version in the base class. In practice, such declarations often are a mistake—the class author intended to override a virtual from the base class but made a mistake in specifying the parameter list.
Finding such bugs can be surprisingly hard. Under the new standard we can specify override
on a virtual function in a derived class. Doing so makes our intention clear and (more importantly) enlists the compiler in finding such problems for us. The compiler will reject a program if a function marked override
does not override an existing virtual function:
struct B {
virtual void f1(int) const;
virtual void f2();
void f3();
};
struct D1 : B {
void f1(int) const override; // ok: f1 matches f1 in the base
void f2(int) override; // error: B has no f2(int) function
void f3() override; // error: f3 not virtual
void f4() override; // error: B doesn't have a function named f4
};
In D1
, the override
specifier on f1
is fine; both the base and derived versions of f1
are const
members that take an int
and return void
. The version of f1
in D1
properly overrides the virtual that it inherits from B
.
The declaration of f2
in D1
does not match the declaration of f2
in B
—the version defined in B
takes no arguments and the one defined in D1
takes an int
. Because the declarations don’t match, f2
in D1
doesn’t override f2
from B
; it is a new function that happens to have the same name. Because we said we intended this declaration to be an override
and it isn’t, the compiler will generate an error.
Because only a virtual function can be overridden, the compiler will also reject f3
in D1
. That function is not virtual in B
, so there is no function to override. Similarly f4
is in error because B
doesn’t even have a function named f4
.
We can also designate a function as final
. Any attempt to override a function that has been defined as final
will be flagged as an error:
struct D2 : B {
// inherits f2() and f3() from B and overrides f1(int)
void f1(int) const final; // subsequent classes can't override f1 (int)
};
struct D3 : D2 {
void f2(); // ok: overrides f2 inherited from the indirect base, B
void f1(int) const; // error: D2 declared f2 as final
};
final
and override
specifiers appear after the parameter list (including any const
or reference qualifiers) and after a trailing return (§ 6.3.3, p. 229).