- COMP.CS.140
- 5. Inheritance
- 5.1 Modularity: Inheritance
- 5.1.2 Inheritance
Inheritance¶
The classification and categorization of things is natural to humans. Inheritance is a commonly used feature of object-oriented programming where a new class is created based on an existing model, i.e. another class. This ability to create new classes on the basis of another class can be said to be one of the most important features of object oriented programming and object-oriented design. In inheritance a class is based on another class so that the class inherits the features of the class it is based on. New features can be added to the class created by inheritance and the features of the class that acted as the base class can be changed if needed. The classes form thus inheritance or class hierarchies – inheritance trees where the classes lower in the tree inherit the features of the classes above.
Key terms of inheritance:
Inheritance: Creation of a new class based on an existing class so that the new class has all the features of the prior class.
Base class (also super class, parent class): The original class higher up in the class hierarchy. The features of the base class are inherited by the new class.
Subclass (also derived class): The new class that inherits the features of the original, i.e. the base class. New features can be added in addition to the inherited ones.
Inheritance hierarchy (also class hierarchy): A tree structure formed by the base and sub classes. The classes lower in the inheritance hierarchy inherit the features of the classes higher up.
Ancestor: the base class met in the class hierarchy when going up as well as its base class and the base class of its base class etc.
Descendant: The classes inherited from the base class and the classes inherited from them.
The classes in the upper parts of the class hierarchy act as top level concepts that define the interface of the classes lower down. Their role is to group actual classes together based on their joint interface or functionality. In the class hierarcy depicting organisms, classes that can be instantiated as objects are the lower level classes Platypus, Human, Hen and Nightingale. The role of these is to implement the services defined on the base class level in a way suitable for the class in question. Inheritance separates the interface from its implementation: the interface is defined on the base class level, the subclass implements it in the way it wants, i.e. it specializes functionality defined higher up in the hierarchy. Classes on higher levels such as Organism and Bird have been marked with “{Abstract}”. This means they are classes used for grouping common functionality and it is not sensible to make objects out of them. They can also have services in their interface that are not implemented at all on the level of the base class. Such classes are called abstract base classes.
The inheritance hierarchy depicts relationships between classes.
With organisms, the class Organism contains the interface common to all organisms: all organisms are able to reproduce.
This means that each organism in the program will reproduce in the program in a way that looks and can be called the same on the outside.
The implementation of the feature can vary a lot between the classes: a platypus and a chicken reproduce very differently.
Derived classes such as Bird ang Fungus offer automatically in their interface the services provided by Organism.
To this they add their own services specific to the class. For example a Bird can also sing.
The benefit of inheritance is that with it all mammals can be referred to by using the class Mammal.
A good example of this in Java is the equals
comparison that is possible for any Java class, i.e. an Object
.
Also if a new service needs to be added to the Birds in the program it is enough to add it to the class
Bird
.
The platypus is a great example of how difficult it is to depict natural phenomena hierarchically as the platypi are mammals that lay eggs. In addition to that, they are duckbilled. It is good to keep in mind that inheritance hierarchies are always dependent on the situation and the classes used in a program do not always directly match the actual or defined objects. For example the staff of the university can be represented in two very different hierarchies.
Classes have different roles in the hierarchy depending on their location in the inheritance tree:
Interfaces or interface classes define only an interface which some other class implements
Abstract base classes define the common interface and functionality of the subclasses but they cannot be instantiated (they are not necessarily fully implemented)
Concrete classes implement their complete interface and can be instantiated.
The main motivators for using inheritance are the reuse of functionality (collecting the common functionality as part of the base class) and specialization and extension (in addition to the base class interface new services are implemented in the subclass or some base class implementation is changed in the subclass)
Reuse: generalization¶
It is quite common that classes have common features. For example all elements drawn on the screen act in a certain way. In these situations it is useful to collect functionality shared by the classes into a base class from which the shared functionality is inherited into the subclasses. Subclasses avoid the reimplementation done on the base class level. The collection of shared parts under a common base class is called generalization. Generalization improves the maintainability of program code. In addition it is easier to ensure its correct functionality when only one shared implementation needs to be tested. Generalization enables code reuse: a feature implemented in the base class does not need to be implemented again. On the other hand generalization renders code to long inheritance chains which makes the code structure more fragmented. The code is then harder to read and the program functionality is more difficult to follow as the implementation is fragmented onto several levels of hierarchy. The use of inheritance thus emphasizes the importance of documentation.
Extension and Specialization of Functionality¶
Generalization brings with it the possibility to add own services into the subclass in addition to the shared functionality that comes from the base class. This simple and already familiar way from earlier courses to use inheritance is called the extension of the implementation. The functionality defined in the base class is taken as it is (reuse) and additional services needed for the subclass are added (extension). It is important to remember that using inheritance is not necessarily needed for extending the functionality. It is worth to extend the functionality of the base class if both the base class and the extended subclass are needed. It is also possible to just add functionality into the base class itself.
Specialization mentioned earlier is probably the most used way of inheritance. There the subclass is a specialized version of the base class: its outside behaviour matches the interface of its base class but the functionality can be specific to the subclass.
The different ways to use inheritance complement each other. When designing objects, it is important to think through, what approach suits the situation best and also if inheritance is needed in the first place.
Is-a relationship¶
The subclass inherits all features of the base class. Its interface is thus the same as the base class interface. A key concept that determines if there is an inheritance relationship between two objects is the so called is-a relationship: an object of the subclass is also an object of the base class. From the point of view of inheritance the is-a relationship defines whether an inheritance relationship exits between two concepts in the program. A dog is-a(n) animal, a chicken is-a bird, a string array is-a(n) array, etc. It can in some situations make sense to use an inheritance relationship even though there is no direct is-a relationship between the concepts. However, it is mostly reasonable to assume that if an is-a relationship does not exist, inheritance should not be used either.
In addition to is-a relationships has-a relationships are formed: an object of a class consists of certain types of objects. A car has-a motor, a library book has-a return date, etc. Has-a relationship defines a composition: an object has as a part of its implementation another object.
When investigating the inheritance hierarchy from the point of view of the is-a relationship it can be seen how subclass objects are also base class objects.
Each subclass object has also the base class parts: they are formed as layers of their base class parts and finally adding the part for their own functionality.
Even if the subclass object has its base class parts it doesn’t automatically have access
to the internal implementation of the base class. Just like external users, the subclass needs
to access the base class part through the public interface of the base class.
The base class can also offer a special interface for its subclasses – protected
.
Inheritance (duration 22:07)
Polymorphism¶
Probably the most important benefit inheritance brings into programming is the possibility to handle objects of different types in a uniform way through their common base class. This is called polymorphism (from Greek poly (many) morphos (form)). Because a subclass object is also an object of its base class, it can be handled as its base class object in the program. This is what polymorphism is about: objects of different types can be referred to through a common name with the help of their base class.
Polymorphism can be seen in practise by looking at the inheritance hierarchy. It has been defined in Animal that all animals can move. It is hence possible to tell all animals in the program to move without having to worry which animal is in question. As the implementation for moving is very different for different objects, it may be necessary to determine at runtime which concrete implementation is to be called. This is called dynamic or late binding.