Inheritance
If inheritance promises one thing, it is generic code—the Holy Grail of programming. The more generic the code is, the wider its scope for reuse.
How does inheritance help with producing generic code? It provides the following six key features that fulfill the requirements for generic code:
- Base classes
- Derived classes
- Information hiding
- Separation of concerns
- Code encapsulation
- Virtual destructors
I’ll now use some code from a previous article (see [2] in the "Additional Reading" section) to illustrate how inheritance facilitates the creation of generic solutions.
The code in question models a simple document management system and features a base class called AnyOldDocument that represents all document types. More specialized document types subclass the AnyOldDocument base class. Examples of such subclasses are InvoiceDocument and ContractDocument, respectively.
Listing 8 is an excerpt from the base class.
Listing 8 The AnyOldDocument base class
class AnyOldDocument { public: AnyOldDocument(); AnyOldDocument(int Id, char* name, int docType); AnyOldDocument(int Id, char* name, int docType, int theNumber); virtual ~AnyOldDocument(); const int GetAssociatedNumber() { return associatedNumber; }; void SetAssociatedNumber(int newNumber) { associatedNumber = newNumber; }; virtual void StoreDocument() {}; virtual void GetDocument() {}; virtual void DeleteDocument() {}; private: int documentId; char * documentName; int documentType; int associatedNumber; };
So how does the Listing 8 base class fulfill the generic code requirements? Well, it’s a base class (item 1) and it allows for derived classes (item 2). The AnyOldDocument class provides information hiding in the form of its private data members (documentId, documentName, and so on). Subclasses don’t have to worry too much about representing the data in the base class private data members.
How about separation of concerns? (Separation of concerns represents the clear definition of the major functions of a software system.) Again, a good base class separates out key elements of the software solution; for example, representing document type and document IDs. By locating generic code in the base class, you help to improve the degree of code encapsulation.
Finally, notice the virtual destructor in Listing 8. The use of virtual destructors is often a missed programming opportunity. Just one line in your base class can provide so much power!
The above illustrates why base classes and inheritance provide the means for producing very generic code. With little or no extra effort, your class hierarchies then more closely model the underlying real-world elements. This also makes for better separation of concerns, which in turn helps to clearly delineate key elements of your solutions.
Finally, employing virtual destructors helps to ensure that your code doesn’t leak system resources. Even the biggest and most powerful platforms in the world can be brought to their knees by leaky code! So we should all do our best to write generic code.