When several different classes that support the same protocol are implemented, there could be a lot of repetitive coding. Rather than duplicate code in different classes, most object-oriented systems allow for the sharing of the implementation of operations, by mechanism called inheritance. Using inheritance, one class can be defined as basically similar to another, and just the ways in which they differ can be implemented. Indeed, in the early days of object-oriented design, the use of inheritance was called programming by difference.
Consider the classes and their respective operations, shown in Table 1.
|balance(): Money||balance(): Money|
Clearly, there is some overlap between the two lists. Each class provides an operation called balance, which returns the current balance. It probably makes sense for both classes to implement this in the same way – say to store some private data representing the balance and return the current value. The code for the credit operations is probably identical, but the code for the debit operation is probably not identical, because SavingsAccount may have different restrictions for withdrawal. SavingsAccount also provides many operations that are special to saving accounts which ordinary account do not have.
Thus SavingsAccount is similar to Account but with a different implementation of debit and some extra operations. This is expressed in object-oriented languages by saying that SavingsAccount is A subclass of Account. A subclass (here SavingsAccount) inherits all the operations of the superclass (here Account), but it may add some extra ones, and it may override some of the inherited ones by providing definitions of its own. SavingsAccount has all the operations of Account, but it also has some extra ones, and it overrides the debit operation with a different implementation of its own. A subclass always has the whole protocol of its superclass.
The subclass is allowed to add extra operations, and to override existing operations of the superclass, but it is not allowed to remove operations. CurrentAccount could not be defined as SavingsAccount without the operations to do with handling interest. The reason for this becomes apparent if protocols are considered. The protocol of Account is (credit debit, balance). If subclasses are allowed to add operations, and redefine operations, the subclasses of Account will still support the same protocol. (They may also support other protocols, but that is not the issue here.) If both Account and SavingsAccount support a shared protocol, they can be used in the same way by other classes. For example, there might be a club which keeps its assets in an instance of Account. It could change to using SavingsAccount without needing to modify the club at all, because the club will be written to use the protocol of Account, and all subclasses of Account necessarily support the same protocol as Account. Figure 7 shows an inheritance tree for Account and SavingsAccount.
The open arrowheads between classes represent the inheritance relation, going from subclass to superclass. They could be verbalised as ‘is a kind of’ (or ‘is-a’).
One purpose of inheritance is to allow two different classes to share code. Sometimes this results in the creation of classes that do not represent anything in the problem. They are there simply to enable code to be shared. For example, in a word-processing application, there might be the classes Paragraph and Picture, in which several operations were identical. The cut, paste and copy operations might be identical, and so to save repetitive coding, both Paragraph and Picture could be made subclasses of new class, DocumentElement, and the shared operations put in that class. Such a class is called an abstract class. It is created solely for the purposes of sharing code between subclasses and there should never be any instances of DocumentElement.
Some object languages allow for multiple inheritance, in which a class is allowed to inherit from several superclasses. For instance, Car class might inherit both from Vehicle and from FinancialAsset. The merits and problems of multiple inheritance are much discussed among designers. Some languages, like Smalltalk or Java, do not implement multiple inheritance; they allow only a single superclass for any class.
The components that make up a graphical user interface (GUI) are often called widgets. Arrange the classes VerticalScrollBar, Widget, Button, IconButton, ScrollBar, HorizontalScrollBar into an inheritance tree.
The class Transporter represents anything that transports people. Design two different inheritance trees to hold the classes Ferry, Dinghy, Car and Bus – one in which the most important distinction is between public and private transport, the other in which the primary division is between water and land transport. You will have to create some extra classes.
Arrange the classes Person, Doctor, Patient, Surgeon, Anaesthetist, InPatient and OutPatient into an inheritance tree.
The following figures show some candidate trees.
Observe that an object, once created, belongs to only one class and cannot change classes. In the medical example, if a world in which doctors may become patients, or out-patients may become in-patients were to be modelled, this would not be an appropriate representation. Whether or not an inheritance structure is appropriate depends entirely on what is to be done with the objects.