QM Bites : Maximising Discoverability of Virtual Methods

QM Bites : Maximising Discoverability of Virtual Methods

By Matthew Wilson

Overload, 24(131):24-25, February 2016


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:

  1. The virtual method SomeMethod() is defined and implemented only within the class MidLevel (and may be overridden by derived types);?
  2. The virtual method SomeMethod() is defined by the class TopLevel (or one of its ancestors) in which it is pure, so MidLevel::SomeMethod() is (at this level) its one and only definition;?
  3. The virtual method SomeMethod() is defined and implemented by the class TopLevel (or one of its ancestors) so MidLevel::SomeMethod() is an override (which may or may not invoke TopLevel::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).






Your Privacy

By clicking "Accept Non-Essential Cookies" you agree ACCU can store non-essential cookies on your device and disclose information in accordance with our Privacy Policy and Cookie Policy.

Current Setting: Non-Essential Cookies REJECTED


By clicking "Include Third Party Content" you agree ACCU can forward your IP address to third-party sites (such as YouTube) to enhance the information presented on this site, and that third-party sites may store cookies on your device.

Current Setting: Third Party Content EXCLUDED



Settings can be changed at any time from the Cookie Policy page.