C++11 introduced override as a contextual keyword. Matthew Wilson encourages us to use it.
TL;DR:
Reduce opacity in C++ inheritance hierarchies w
override
k/w (or comments in C++03/earlier)
Bite:
One of the myriad sources of confusion about C++’s ambiguous syntax is in determining whether or not a virtual function is one prescribed in the type one is currently examining or prescribed from a parent class. Consider the following:
class MidLevel
: public TopLevel
{
. . .
virtual void SomeMethod();
};
There are several possible interpretations:
-
The virtual method
SomeMethod()is defined and implemented only within the classMidLevel(and may be overridden by derived types);? -
The virtual method
SomeMethod()is defined by the classTopLevel(or one of its ancestors) in which it is pure, soMidLevel::SomeMethod()is (at this level) its one and only definition;? -
The virtual method
SomeMethod()is defined and implemented by the classTopLevel(or one of its ancestors) soMidLevel::SomeMethod()is an override (which may or may not invokeTopLevel::SomeMethod()in its implementation);?
The only way to know is to examine the definition of the class
TopLevel
, or the definition of (a) parent class of
TopLevel
, or the definition of (a) grandparent class of
TopLevel
, or …
Application of the C++ 11 keyword override is a boon to discoverability, in that it connotes that the method is an override of a method declared/defined by a parent class. Hence, Listing 1 implies either case 2 or 3 above.
class MidLevel
: public TopLevel
{
. . .
virtual void SomeMethod() override;
};
|
| Listing 1 |
With C++-98/03 (or any compiler that does not support C++ 11’s override), an alternative declarative technique is simply to use a comment, as in Listing 2, or object-like pseudo-keyword macro (that resolves to
override
with compilers that support the keyword, and to nothing with those that do not), as in Listing 3 and Listing 4.
class MidLevel
: public TopLevel
{
. . .
virtual void SomeMethod() /* override */;
};
|
| Listing 2 |
#ifdef ACMESOFT_COMPILER_SUPPORTS_override_KEYWORD # define ACMESOFT_override_K override #else # define ACMESOFT_override_K #endif |
| Listing 3 |
class MidLevel
: public TopLevel
{
. . .
virtual void SomeMethod() ACMESOFT_override_K;
};
|
| Listing 4 |
Of course, the virtue of the new keyword is far greater than that of connotation of design intent – it facilitates enforcement of design intent. If Listing 1 is presented to the compiler in case 1, it will be a compiler error, since one cannot override something that does not (previously) exist. That’s great.
Just as importantly, it guards against coding errors and/or design changes, in requiring that the overriding method matches the overridden method. If Listing 1 compiles, but then the method signature (or return type, or cv-qualification, or universality) changes in the parent class – the fragile base class problem – it will be a compile error. That’s great too.
(Obviously, neither the comment-form nor the macro-form do any enforcement with non-C++-11-compatible compilation, but it still is a non-trivial amount of help for the human side of things.)
Prior to the advent of
override
my practice was to distinguish between case 1 and cases 2/3 by placing the
virtual
keyword in comments, as in Listing 5.
class MidLevel
: public TopLevel
{
. . .
/* virtual */
void SomeMethod() ACMESOFT_override_K;
};
|
| Listing 5 |
Should you wish, you may do this too, but since
override
does a superior job in connoting overriding, you might prefer to elide it completely, as in Listing 6.
class MidLevel
: public TopLevel
{
. . .
void SomeMethod() ACMESOFT_override_K;
};
|
| Listing 6 |
After all this you might be wondering what we do about distinguishing between cases 2 and 3. That’s another story (but if I give you a hint and suggest that case 3 is pretty much a design smell, pertaining to modularity as well as discoverability , you might get there before we visit that subject in this place).









