Everything You Need to Know About Polymorphism
Polymoprhism’s use and benefits

In this piece, we will look at everything you need to know about polymorphism. The name might incline you to believe it’s difficult, but in fact, polymorphism is easy to understand.
Polymorphism does require an understanding of inheritance, and this piece’s code samples are in C++, so if you’re unsure as to what inheritance is, then maybe come back and read this piece once you’re familiar.
For those who have heard the concept but need a refresher, I’ll provide a quick recap before jumping into polymorphism.
Quickly Recapping Inheritance
Inheritance is a concept that allows us to reuse code through an is-a relationship. We have a class, Soldier
, which has certain behaviours and states. It might have health, stamina, and behaviours such as walking, fleeing, and shooting. A class can inherit these behaviours from the base class Soldier
whilst also incorporating its own. We could have a class JetpackSoldier
which inherits from Soldier
. JetpackSoldier
can do everything Soldier
can in addition to having their own behaviours, such as being able to fly.
It’s possible to override the behaviours defined in the base class. For example, if we wanted a jetpack soldier to flee by flying away from the player, as opposed to just running away like a normal soldier, we can do this by overriding the flee method in the JetpackSoldier class.
If this still doesn’t make much sense, you might need to research inheritance a little more before carrying on with this article. Take your time; this article will still be here when you get back.
What Is Polymorphism?
Polymorphism describes something that takes many forms. In computer science, this refers to functions and objects having multiple forms.
Functional polymorphism
Functional polymorphism is implemented using overloading. Overloading allows functions to share the same name whilst passing in different types and/or a different number of arguments. A single function that has multiple forms.
For example, consider a function that sums two numbers. We could have a sum function that takes in two integers and returns an int, and another sum function that accepts two floats as arguments, returning a float. When we call sum passing in two numbers, the compiler will work out which method actually needs to be called based on the parameters we have passed. In either case, we can obtain different behaviour when calling methods that share the same name depending on the parameters we pass.
Object polymorphism
Polymorphism regarding objects is slightly different. This is where inheritance comes into play. For any object with a base class, say our JetpackSoldier
class, whose base class is Soldier
, we can instead treat it as if it was a Soldier
. Any code that handles anything to do with the Soldier
objects can also work with JetpackSoldier
objects as well. The benefits are best shown with an example:
If we assume we have vehicles in our game and we have a class Jeep
, we would like to store a reference in this class to the soldiers driving around in this vehicle. Let’s say that our jeep stores a maximum of four people; how would we do this in code? Polymorphism handles this easily.
A simple way of handling this problem is to have a reference to Soldier
for each seat in the jeep, two in front, two in back. Because polymorphism enables us to treat objects as other objects, JetpackSoldier
as Soldier
, we can add both JetpackSoldier
and Soldier
objects to the Jeep
class. If we add more soldiers to our game, as long as they inherit from Soldier
, they too can be added to the jeep class.
Sticking with the same example as before, if we want to store different soldier types, we’d have to add additional member variables and methods to support this. We also need more checks before we can put a soldier in the jeep.
As you have probably guessed, as our game gets more complicated and we have many variations of Soldier
, the Jeep
class will get increasingly more complex as we try to support all different soldiers getting into the vehicle.
The Benefits of Polymorphism
From the previous section, we can see that one advantage of polymorphism is that it allows us to reuse existing code, which can make things easier to read and maintain.
However, another big advantage that we only briefly touched on is that polymorphism allows us to “hide implementation details by interacting with a group of different classes through a common interface.” This means we can have a class that interacts with a lot of objects that all inherit from the same base class through the methods that these objects share. The shared methods are known as the interface.
What makes this even better is that just because we call the same method on all our Soldier
objects, that doesn’t mean they all do the same thing. Recall that when calling flee on objects of type JetpackSoldier
, they will flee by flying away as opposed to running, having overridden the method in the base class Soldier.
The benefits of interacting with objects with a shared interface are all the things we’ve talked about as well as limiting the amount of coupling between our classes. Coupling is the idea that our code can get tightly linked together, which makes it hard to change without breaking stuff. If we added extra soldiers into our game, our SquadCommander class need not change as long as the solider types all share that common interface.
Note: If we add or subtract from the interface, classes like SquadCommander that rely on that interface need to change, either to accommodate the new behaviour or to remove behaviour that is no longer needed. The important thing is that we can add additional soldier types and not have to change anything.
Polymorphism and Performance
However, as wonderful as polymorphism can be, there is arguably one disadvantage, its potential impact on performance.
Until now, we’ve discussed how polymorphism allows us to call objects that all inherit from some base class through a single interface whilst also enabling us to call the methods specific to that class. If we have a JetpackSolider
class stored in a variable of type Soldier
and call Flee()
, the solider will still fly away instead of running, even though it’s stored as a Soldier
.
The same thing that allows this behaviour can also cause performance problems with our code.
I won’t go into a huge amount of detail about exactly how polymorphism is implemented in C++. I have left several links at the bottom of this piece that explain well if anyone is interested.
All you need to know for our purposes is that polymorphic behaviour is enabled in C++ using something called a virtual table. A virtual table is an array that stores the addresses of all the virtual functions for a class. When a call is made on a virtual function, the code must navigate to the virtual table, look up which function to call, then go to the address and call to the function. With a normal non-virtual function, we simply go to the function’s address. In certain situations where the computer is already doing a lot of work, these extra steps can slow things down.
When I say in certain situations, I do mean in certain situations. In general, the performance issues that can arise from using polymorphism won’t be a cause for concern. But I thought it was worth mentioning; to have a complete understanding of polymorphism, it’s important to understand any advantages and disadvantages. It’s not worth losing the flexibility that comes with object polymorphism in favour of performance unless you know it’s causing an issue. It’s best to embrace polymorphism and only think about removing it if it’s an issue. And that’s shown by profiling, not by just thinking that :P
Summary
Polymorphism is inherently good. It refers to something having many forms, referring to both objects and methods. Polymorphism allows you to code to an interface that reduces coupling, increases reusability, and makes your code easier to read. Performance may degrade when using polymorphism in some situations, but this doesn’t mean we should avoid it.