This is part of my rough notes and will probably be cleaned up and tweaked over time.
##Polymorphism
Polymorphism is the ability of subclasses to redefine the functionality of a parent class.
It is closely related to, but is not the same as, inheritance. The key word is redefine.
It's important to understand where Polymorphism and Inheritance differ, so let's do a comparison:
####Pure Inheritance A class that inherits from a parent class contains all the functionality of that class.
A class Character
might have the function walk
.
Two new classes, Mage
and Rogue
, can inherit from Character
so that they both have the ability to move around.
In both sub-classes walk
can be implemented the same way:
/* move in current direction */
public void walk(int distance)
{
positionX += distance * cos(direction);
positionY += distance * sin(direction);
}
This is basic inheritance, where derived classes contain all functionality of parent classes and can add more functionality to it.
In terms of how inheritance is implemented, it can be as simple as the derived class having an object of the base class within it. So functionality can literally be copied over, as-is, to the derived class.
####How Polymorphism is Different Polymorphism goes a step further. It is the ability of sub classes to overwrite pre-existing functionality. i.e. a polymorphic class can have the same functions as its parent class, but those functions can have completely different implementations.
If we gave Character
the function attack
, our two derived classes, Mage
and Rogue
, will need different versions of it.
For the mage
:
public void attack()
{ /* attack using staff */ }
For the rogue
:
public void attack()
{ /* attack using dagger */ }
In terms of implementation, polymorphism is trickier than pure inheritance due to one question:
which implementation of dock
must be used?
The full answer depends on the specifics of the language and how the function is coded, but basically and in general:
- we can use the most low-level version (e.g. in
Character
)- this is how a lot of compilers are set up by default
- we can choose a version somewhere along the way, if there is a chain of inherritance
- this requires language-specific shenanigans - for example this can be achieved in C++ by using different pointer types
- this is not very widely used, usually there are easier ways to do this
- we can use the most high-level version (e.g. in
Rogue
orMage
)- functions that enforce this are called
virtual
functions - polymorphism is mainly intended for this case
- functions that enforce this are called
####Why It's Useful (to me)
One of the great things that you can do with Polymorphism is that you can assign a child class to an object of a base class.
For example:
Character player = new Rogue();
This is really useful, because in many applications, you know that you will need to be working with a certain class, but you don't know what kind of sub-class you will be getting. In our example, we know that we will need a character, but we don't know what class our user will choose.
This allows us to just use player.attack()
without needing to worry about whether the player is a mage, a rogue or any other kind of class because the highest level version of walk
and attack
are used. Since player
was assigned a Rogue
object, the version of attack
that will be used is the rogue's version.
####Abstract Classes One of the things that we can do with polymorphism is make classes that only serve as templates for other classes - they aren't meant to be used as-is.
Our example of a character that is then derived into different classes is a pretty good illustration of an abstract class. Without knowing whether the character is a mage or a rogue, the function "attack" doesn't mean much - it's abstract
.
Another classic example of this is a polygon. A polygon has some number of straight sides which form a closed shape, so all we know about a polygon is that it has:
- sides
- an area
- an overall width
- an overall height
But that's basically it. We don't know how to calculate the area of a polygon without any more information: it's abstract
.
We can then derive other shapes from Polygon
: Rectangle
, Triangle
that then have meaningful implementations.