Run-Time Polymorphism in C#
Master the Polymorphism concept
In the last article, we saw what in God’s name Method Overloading is and how we can achieve it. Method overriding is the long-lost sibling of method overloading, but there is one fundamental difference that sets them apart.
This is part 2 of the Polymorphism series, where we are going to take a deep dive into polymorphism. The following are the 3 pieces of the puzzle.
- Compile-time polymorphism
- Run-time polymorphism
- Method hiding/ shadowing
We will compare overriding with overloading which will not only clear the confusion between these two but also give a better understanding of overriding.
Overloading means having multiple behavior where overriding means changing the behavior.
Following are the key differences between overloading and overriding.
- In method overloading, we have to change the signature, whereas in method overriding we have to keep the same method signature including
return-type
andaccess specifier
, it is a technique of reusability. Meaning, redefining the parent class method in the child class with exactly the same signature. - Methods can be overloaded within the same class and within subclasses as well. Whereas overriding methods can only be overridden in a subclass, if you try to override a method within the same class using the same signature, you will get a compile-time exception shown below.
The Exception: Type ‘class name’
already defines a member called ‘method name’
with the same parameter types.
The most important rule: You can only override virtual
or abstract
methods, which means the parent class needs to decorate a method with ‘virtual’
or ‘abstract’
keywords that will allow the child class to override. You can not override methods that are not virtual
or abstract
.
Let’s start coding!
Rule number 1: Method signature should match including
return-type
andaccess specifier
.
Let’s call these methods with their type
to see if this worked?
As you can see in the image-1 below, an instance of parent class SmartPhone
is calling its version of GetOS()
and printing message “Android”
whereas, an instance of child class Iphone
is calling its version of GetOS()
and printing message “iOS”
. This is because we’ve successfully overridden a method GetOS()
in class IPhone
.

Note: If you did not define a method in child class then the child class object will call the parent’s method. If you had code that looks like listing 2, then you’ll get output that looks like image-2.
In the following image 2, you can see both parent and child class objects are calling parent class version of GetOs()

Let’s see a few false scenarios down the line, which are important to understand!!
False scenario 1: what happens if I try to override a method with a different
return type
?
I get the following exception!
The Exception:
‘IPhone.GetOS()’
: return type must be ‘string’ to match overridden member‘SmartPhone.GetOS()’

False scenario 2: what happens if I try to override a method with a different
access specifier
?
I get the following exception!
The Exception:
‘IPhone.GetOS()’
: return type must be ‘string’ to match overridden member‘SmartPhone.GetOS()’

False scenario 3: what happens if I try to override a method which is not
virtual
orabstract
?
I get the following exception of course!
The Exception:
‘IPhone.GetOS()’
: return type must be ‘string’ to match overridden member‘SmartPhone.GetOS()’

Here you might argue that I can simply skip the override keyword in the child class, yes you can but then it won’t be an overridden method. It will be an independent method that belongs to type ‘IPhone’
.
And this is called method hiding when parent and child classes have the same method name with the same signature without ‘virtual’
or ‘abstract’
keywords then the child class hides the implementation of the parent’s class method.
Let’s take one more scenario, this was one of the interview questions as well. What if you have a multilevel inheritance? Something like listing 3:
New grandchild class IphoneX
has its own version of GetOS()
, So with the object of IPhoneX
we get its version of GetOS()
.

The real question is, what if grandchild IPhoneX
doesn’t have a version of the overridden method? so with its object, will it refer to parent’s IPhone’s GetOS()
or grandparent’s SmartPhone’s GetOS()
? Let’s find out.
Listing 4 draws this scenario.

Remember this hierarchy of preferences : Local -> immediate parent -> their parent -> till the base class.
If you look at that, the grandchild ends up calling its parent’s version of GetOS()
. This is because the grandchild first looked in itself if the overridden method exists. If not then it goes to the parent to see if a version of overridden method exists. As it did exist in the parent it stopped its search and accessed the method.
OK!! Now we know that it accesses the immediate method in the case of override
, but what happens when the method is virtual
? Let’s see.
Consider the following scenario:
Here also the same rule applies, it looks for the immediate parent and tries to resolve the matter. In the following image, you can see IPhoneX
is also printing “iOS”
which is its parent’s version of GetOS()
.

Just for fun let’s delete the parent version of GetOS()
as well.

Now that it has reached the base class SmartPhone
and it did find the method with a matching signature, it stopped its searched and printed the output “Android”
.
Now we know what are the different methods of overloading and overriding. And what to avoid while overriding a method, and how to successfully override it.
Want to Connect?Hit me up on LinkedIn.