I am writing this blog post largely in response to John’s blog post: Public Virtual Methods: A Bad Idea. John and I work closely, and have for as long as I have been at Spatial. I like working with him because,
- He is so smart that not devoting full effort to understanding his arguments would be a huge mistake.
- As with anyone else, just nodding along in agreement doesn’t enlighten as much as listening carefully then understanding when an argument is correct and what its limitations are.
John has always been good about thinking over ideas together, so I don’t think this particular post should cause me too much trouble. Before I start my main argument, I should stipulate that in the case where you use inheritance to make some of the implementation of the derived class John’s argument is perfectly correct.
Please examine the following header file snippet:
Is this in any way bad style? Does the interface presented have the problem of trying to serve two purposes?
A purely abstract class (i.e., all virtual pure methods, except destructor which is impure but virtual) merely defines method names and signatures; it just defines syntax for service providers and clients to mediate provision of services. COM utilizes this pattern extensively to good effect. Also, CGM operators follow this pattern: in CGM, clients of the library are not typically expected to derive operators merely make them and use them. Arguably, this programming standard is better than many others one might encounter.
Inheritance makes C++ much more convenient for writing maintainable software then, for example, C or Fortran. But inheritance in general may be more trouble than it is worth. For example, the Gang of Four book (link to Wikipedia http://en.wikipedia.org/wiki/Design_Patterns) argues to "Favor object composition over class inheritance". Even using public inheritance to implement functionality in derived classes runs some risk of coupling between the base class and the derived class. If C++ where modified to allow classes with public and private access, and forbid all forms of inheritance other than inheritance from interfaces (i.e., abstract base classes with only pure virtual methods), I think it would be just as useful as it is now (but a lot more verbose).
The main argument for this point consists of a simple refactoring. Suppose we have an abstract base class with private virtual methods:
We can always write code that does the same thing without inheriting from the implementation as follows:
In the implementation of BaseClass you merely call pd->CustomizableStep1(/*…*/) rather than ABaseClass::CustomizableStep1(/*…*/).
There are a couple of subtleties here:
- I am not advocating removing inheritance of anything other than interfaces from C++. Other inheritance can make code more concise and understandable at some sacrifice of flexibility.
- Contracts (semantics) of service provided is as important (maybe more important) than syntax. This can also be handled conveniently using contract checking and inheritance from interfaces as follows:
Click to Enlarge Image
- Since I am editorializing anyway: the main thing for code flexibility is the ability to parameterize behavior either via interfaces ( like in C++, C#, …) or function objects/closures (as in LISP, Haskell, …).
What do you think?