OOP - Polymorphism
Polymorphism is one of 3 foundational concepts of Object Oriented Programming. Polymorphism can be translated to mean many forms. In OOP, polymorphism means that one object can be considered to have many forms. An object-reference of the base-class type can refer to either a base-class object or a child-class object. Another way to consider this is that when we have a collection of similar objects, where we refer to them with the more generalized format (base-class type object-reference variable), that variable can refer to any of the child-class objects.
In the example below, this is intuitive for us: a dog is an animal, a cat is an animal, an animal is an animal. However, a dog is not a cat, and we can'd force some instance of an animal to be strictly a cat, we would expect this to cause errors as in the example code below.
So, polymorphism means that child-class objects can be to be treated as their more general, base-class type, and this reflects our intuition about relationships between real-world objects. My pet, Charlie, is an instance of a dog object, but he can also be considered as an animal, which would be the more general concept, or base-class concept.
Object References
We can create an object reference variable of the base-class type, and this variable can be used to reference either a base-class object, or any object that is of a child-class type. We can imagine a set of classes, where Animal is the base-class, where Cat and Dog would be child-classes that extend Animal. Below are examples using default constructors to demonstrate using base-class object references to refer to child-class object instances. It is important to note that the reverse is not true, you can not use an object-reference of the Child-class type to refer to a base class object.
Array of base-class object references
Over-riding Methods
OOP Polymorphism means that when a child-class object executes a method, then the 'system' will determine whether to execute a child-class method or a base-class method, by examining the child class definition to see if the method has been implemented in the child-class so that it over-rides the base-class method. Method over-riding allows us to treat objects using the more general, base-class, references, but that the 'system' will determine the run-time type of each object instance, and determine whether a base-class or child-class method will be executed. If a method has not been over-ridden in a child class, the child-class object can still call any method specified in the base-class, the child-class 'gets' everything in the base-class 'for free' when it extends the base-class to become a child-class.
Object Oriented Design
Polymorphism should be considered when designing classes with inheritance relationships. Only methods defined in the base-class can be called on using base-class object references, even if the object refers to a child-class object. Therefore, UML class diagrams provide a graphical representation to aid design and use of OOP classes and objects.
UML Diagram of Inheritance Relationships
The diagram above shows a base-class: Creature, and 3 Child classes: Zombie, Cat, Fish
When creating object reference variables, we specify the data-type of the variable, and this impacts the methods that can be called for the object.
Example 1: Base-class object-reference variable:
This object can call any methods that are specified in the base-class.
This object can not call any methods that are not specified in the base-class, even if they are specified in the child-class for the object's actual data-type:
Example 2: Child-class object-reference variable:
This object can call any methods specified in either it's base-class, or it's own class (Fish)
Object Oriented Design - Add methods to the base-class to provide access to specialized behavior in child-classes.
When designing classes, as in the example above, we should identify any specialized behavior that will be exhibited by any child-class and create a method in the base-class that represents the generalized behaivor.
Example: We have a child-class: Fish, where the fish has a specialized behavior: glubGlub( ). Let's assume that can be considered as a more generalized concept: makeNoise( ), where other child classes might also share this behavior. If we define the method: makeNoise( ) in the base-class, then, within the Fish class, we can over-ride makeNoise( ), and call the glubGlub( ) method within makeNoise( ). Then any base-class object can call makeNoise( ), if the object happens to be a Fish, child-class object, it will have it's glubGlub( ) behavior executed.
The image below shows an improved object-oriented design, so that all methods implemented in the base-class can be called by an object with a base-class type reference variable, and if the object is a child-class object, it'll have specialized behavior because it has provided an over-ride for methods where it has special logic to be executed
Last updated