Skip to content

Instantly share code, notes, and snippets.

@xpcoffee
Last active August 29, 2015 14:10
Show Gist options
  • Save xpcoffee/aa595e377cb5fb54d258 to your computer and use it in GitHub Desktop.
Save xpcoffee/aa595e377cb5fb54d258 to your computer and use it in GitHub Desktop.
Polymorphism

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 or Mage)
    • functions that enforce this are called virtual functions
    • polymorphism is mainly intended for this case

####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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment