C# Polymorphism and Inheritance override the abstract or virtual
Occasionally, programmers get to explain Polymorphism and Inheritance in .NET, I’ve compiled some typical use cases in case they need to be explained without IDE.
We start with
- IDrawable interface which indicates all its implementations have a Draw method.
- Geometry abstract class which contains PrintType() that will be called by the specific implementation.
- Shape class inheriting Geometry is a base of other shapes.
- Rect class is a subclass of Shape.
- Square class is a subclass of Rect. (A specific Rect)
- FilledSquare class is a subclass of Square. (A specific Square)
Here is class diagram for above.

polymorphism
Let’s see the code,
Declare a variable case1 of type IDrawable and initialize case1 Rect, in other words, An IDrawable variable case1 stores the address of Rect object in the memory.
IDrawable case1 = new Rect(); case1.Draw(); Out.WriteLine(Environment.NewLine); // output: // Draw Shape Called // Draw Rect Called // IDrawable doesn't see the new implementation // from Square but it knows the concrete // implementation in Rect because of the override case1 = new Square(); case1.Draw(); // output: // Draw Shape Called // Draw Rect Called // Shape type cannot see it either but // it knows the concrete implementation (case1 as Shape).Draw(); // output: same as above // Geometry type cannot see it either but // it knows the concrete implementation (case1 as Geometry).Draw(); // output: same as above
The two outputs are identical, the reason Draw() in Square is not being called is the concrete implementation of Draw() has been done within Rect for type IDrawable and the sealed indicates there wouldn’t be any more implementation from its sub class for IDrawable. However, we do see Draw() has an implementation in Square, this Draw() actually hides the method in the supper class Shape, but the hiding wouldn’t take place unless the variable type sees the new Draw() implementation. For example, the type of Square or its derived classes. In this case the following code will produce the result. Again this is because Square and its sub classes all see the new implementation of Draw().
// cast it to Square type, // then it sees the new Draw() implementation (case1 as Square).Draw(); // output: // Draw Shape Called // Draw Rect Called // Draw Square Called // Square type sees the new Draw() Square case11 = new Square(); case11.Draw(); // output: same as above // Square type sees the new Draw() case11 = new FilledSquare(); case11.Draw(); // output: same as above // FilledSquare type sees the new Draw() in itself and its parent FilledSquare case12 = new FilledSquare(); case12.Draw(); // output: // Draw Shape Called // Draw Rect Called // Draw Square Called // Draw FilledSquare Called
override provides a concrete implementation for either virtual or abstract method in its super class, the variable type always looks for the closest concrete implementation within the initialized object.
The sealed keyword prevents any more concrete implementation from its derived classes so that it ensures the method behavior for the variable type.
In order to use your own implementation even when the supper method is already sealed override, you have to use a variable type which sees the new implementation.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Out = System.Console; namespace Polymorphism { /// <summary> /// Represents IDrawable interface /// </summary> public interface IDrawable { void Draw(); } /// <summary> /// Represents abstract Geometry class /// </summary> public abstract class Geometry : IDrawable { public abstract void Draw(); public void PrintType() { Out.WriteLine(this.GetType().Name); } } /// <summary> /// Represents Shape class /// </summary> public class Shape : Geometry { public override void Draw() { base.PrintType(); Out.WriteLine("Draw Shape Called"); } } /// <summary> /// Represents Rect class /// </summary> public class Rect : Shape { public sealed override void Draw() { base.Draw(); Out.WriteLine("Draw Rect Called"); } } /// <summary> /// Represents Square class /// </summary> public class Square : Rect { public new void Draw() { base.Draw(); Out.WriteLine("Draw Square Called"); } } /// <summary> /// Represents FilledSquare class /// </summary> public class FilledSquare : Square { public new void Draw() { base.Draw(); Out.WriteLine("Draw FilledSquare Called"); } } }
Download polymorphism solution
