When Not To Inherit
When we’re taught the principles of object-oriented programming, we’re often taught the concept of inheritance with an example like the following:
The base class for all people is
Person. A Lawyer is-a Person, so we writeclass Lawyer : Person. A Woman is-a Person, so we haveclass Woman : Person. A Nun is-a Woman, so we writeclass Nun : Woman.
And so forth. Of course, the purpose of this example is to show the idea of the “is-a” relationship, and it’s completely useful for that purpose, though you’d rarely see a class hierarchy just like this in a real application.
You can find lots of lists of when you should use inheritance on the web, in textbooks and so forth. According to one from Microsoft, you should use inheritance when:
- Your inheritance hierarchy represents an “is-a” relationship and not a “has-a” relationship.
- You can reuse code from the base classes.
- You need to apply the same class and methods to different data types.
- The class hierarchy is reasonably shallow, and other developers are not likely to add many more levels.
- You want to make global changes to derived classes by changing a base class.
Okay, well this is relatively straightforward, I suppose. However, I’ve often encountered classes in my applications that could share a lot of common code in a base class, but that I never want to interchange with the base class. The ability to interchange derived classes with the base class is called polymorphism. I want the complier to protect me from myself, and, if I can use the type system to prevent me from doing the wrong thing or confusing one object for another, then I want to do that. So I want to protect myself from using derived classes in place of the base class.
For example, one of the products that I work on examines air bookings. Each flight has-a DepartAirport and an ArriveAirport. So we have our Flight class that has a DepartAirport member and an ArriveAirport member. But the question is, should DepartAirport and ArriveAirport inherit from a common base class, BaseAirport? Logically, both have an is-a relationship with an airport, so they satisfy condition #1 above. There could be code reuse (condition #2), since both airport types share a lot of the same fields, such as latitude and longitude, airport IATA code, local time zone, etc. Condition #4 nominally applies, although I’m not sure that’s something I usually give much consideration. If we moved all the common code to the base class, it might be nice to make global changes in the base class, so condition #5 applies as well.
This just leaves us with the question of #3: do I want to be able to use DepartAirport and ArriveAirport as BaseAirport objects? I’ll spare you the suspense and just say that the answer to that turned out to be “no”, for several reasons that are a bit too involved (and possiblity proprietary) to go into here. Suffice it to say that most of the interesting operations that you could do on BaseAirport objects (find the distance between two airports, find the journey time of a flight taking into account the time zone differences, etc.) generally should take one DepartAirport object and one ArriveAirport object, so there was no situation where we actually saw ourselves using the BaseAirport class by itself. In fact, since we wanted to protect ourselves from doing The Wrong Thing in the code, we wanted to make it impossible to operate on airports outside of the context of whether they were departure or arrival airports.
So, could there still be a way to take advantage of the code reuse potential, while not allowing ourselves the potential polymorphic misuse of the base class?
Well, if we were using C++, we might be able to use private inheritance to gain access to the protected members of the base class, without allowing polymorphism. This app was written in C#, so that wasn’t an option. Could we do some kind of mojo with private inner classes or internal (or package, in Java) classes? Not really, since a base class has to be at least as accessible as its derived classes.
So, finally, we come to the the point. Despite the fact that DepartAirport and ArriveAirport have an is-a relationship with BaseAirport, it makes more sense in the code to consider this relationship to be a has-a relationship, and eschew inheritance entirely. This is sometimes known as “composition” in object-oriented design. DepartAirport and ArriveAirport both contain BaseAirport objects as member variables and allow access to the common members of the base object, but they can never be interchanged with the BaseAirport object, since they don’t inherit from it.
Remember that your object hierarchy does not have to strictly correspond with a “real world” object hierarchy. The is-a relationship is the most common reason why people begin to discuss inheritance, but it’s only one of the reasons to use inheritance, and if you don’t want the other consequences of inheritance, then you should consider an alternative to get the behavior you want.

September 4th, 2008 at 2:36 pm
[...] much better. I’m not sure I really understood all the nuances of inheritance until I wrote a post about it. Additionally, there’s always the (slim) possibility that someone else will benefit from the [...]