C# - Polymorphism



The word polymorphism means having many forms. In object-oriented programming paradigm, polymorphism is often expressed as 'one interface, multiple functions'.

There are two types of polymorphism:

  • Compile Time Polymorphism / Static Polymorphism
  • Run-Time Polymorphism / Dynamic Polymorphism

In static polymorphism, the response to a function is determined at the compile time. In dynamic polymorphism, it is decided at run-time.

1. Static Polymorphism

The mechanism of linking a function with an object during compile time is called early binding. It is also called static binding. C# provides two techniques to implement static polymorphism. They are −

  • Function overloading
  • Operator overloading

We discuss operator overloading in next chapter.

Function Overloading

You can have multiple definitions for the same function name in the same scope. The definition of the function must differ from each other by the types and/or the number of arguments in the argument list. You cannot overload function declarations that differ only by return type.

Example

In the following example, we demonstrate function overloading, a type of polymorphism where multiple methods in the same class share the same name but have different parameter lists. Here, the print function is working as a function overloading −

using System;
namespace PolymorphismApplication {
   class Printdata {
      void print(int i) {
         Console.WriteLine("Printing int: {0}", i );
      }
      void print(double f) {
         Console.WriteLine("Printing float: {0}" , f);
      }
      void print(string s) {
         Console.WriteLine("Printing string: {0}", s);
      }
      static void Main(string[] args) {
         Printdata p = new Printdata();
         
         // Call print to print integer
         p.print(5);
         
         // Call print to print float
         p.print(500.263);
         
         // Call print to print string
         p.print("Hello C++");
         Console.ReadKey();
      }
   }
}

When the above code is compiled and executed, it produces the following result −

Printing int: 5
Printing float: 500.263
Printing string: Hello C++

Operator Overloading

C# operator overloading is a type of polymorphism where you can overload operators by defining special static methods within a class. The overloaded operator must take at least one operand of the class or struct type.

Example

In the following example, we demonstrate operator overloading, where the + operator is overloaded to perform addition on objects of a user-defined class Box. This showcases how polymorphism allows customizing the behavior of operators −

using System;
namespace PolymorphismApplication {
   class Box {
	  // Length, Breadth, and Height of a box
      private double length;
      private double breadth;
      private double height;

      public Box(double l, double b, double h) {
         length = l;
         breadth = b;
         height = h;
      }

      public double Volume() {
         return length * breadth * height;
      }

      // Overloading the + operator
      public static Box operator +(Box b1, Box b2) {
         return new Box(b1.length + b2.length, b1.breadth + b2.breadth, b1.height + b2.height);
      }

      public void Display() {
         Console.WriteLine("Dimensions: {0} x {1} x {2}", length, breadth, height);
      }

      static void Main(string[] args) {
         Box box1 = new Box(3.0, 4.0, 5.0);
         Box box2 = new Box(2.0, 3.0, 4.0);
         Box box3;

         // Add two Box objects
         box3 = box1 + box2;

         Console.WriteLine("Box 1:");
         box1.Display();

         Console.WriteLine("Box 2:");
         box2.Display();

         Console.WriteLine("Resultant Box after addition:");
         box3.Display();

         Console.ReadKey();
      }
   }
}

When the above code is compiled and executed, it produces the following result −

Box 1:
Dimensions: 3 x 4 x 5
Box 2:
Dimensions: 2 x 3 x 4
Resultant Box after addition:
Dimensions: 5 x 7 x 9

2. Dynamic Polymorphism

C# allows you to create abstract classes that are used to provide partial class implementation of an interface. Implementation is completed when a derived class inherits from it. Abstract classes contain abstract methods, which are implemented by the derived class. The derived classes have more specialized functionality.

Here are the rules about abstract classes −

  • You cannot create an instance of an abstract class

  • You cannot declare an abstract method outside an abstract class

  • When a class is declared sealed, it cannot be inherited, abstract classes cannot be declared sealed.

Example

Here, this is an example of the dynamic polymorphism to demonstrate an abstract class and method overriding in the C# −

using System;
namespace PolymorphismApplication {
   abstract class Shape {
      public abstract int area();
   }
   
   class Rectangle:  Shape {
      private int length;
      private int width;
      
      public Rectangle( int a = 0, int b = 0) {
         length = a;
         width = b;
      }
      public override int area () { 
         Console.WriteLine("Rectangle class area :");
         return (width * length); 
      }
   }
   class RectangleTester {
      static void Main(string[] args) {
         Rectangle r = new Rectangle(10, 7);
         double a = r.area();
         Console.WriteLine("Area: {0}",a);
         Console.ReadKey();
      }
   }
}

When the above code is compiled and executed, it produces the following result −

Rectangle class area :
Area: 70

Method Overriding

When you have a function defined in a class that you want to be implemented in an inherited classes, you use virtual functions. The virtual functions could be implemented differently in different inherited class and the call to these functions will be decided at runtime.

Dynamic polymorphism is implemented by abstract classes and virtual functions.

Example

The following example demonstrates dynamic polymorphism using method overriding. It follows the oops principles −

using System;
namespace PolymorphismApplication {
   class Shape {
      protected int width, height;
      
      public Shape( int a = 0, int b = 0) {
         width = a;
         height = b;
      }
      public virtual int area() {
         Console.WriteLine("Parent class area :");
         return 0;
      }
   }
   class Rectangle: Shape {
      public Rectangle( int a = 0, int b = 0): base(a, b) {

      }
      public override int area () {
         Console.WriteLine("Rectangle class area :");
         return (width * height); 
      }
   }
   class Triangle: Shape {
      public Triangle(int a = 0, int b = 0): base(a, b) {
      }
      public override int area() {
         Console.WriteLine("Triangle class area :");
         return (width * height / 2); 
      }
   }
   class Caller {
      public void CallArea(Shape sh) {
         int a;
         a = sh.area();
         Console.WriteLine("Area: {0}", a);
      }
   }  
   class Tester {
      static void Main(string[] args) {
         Caller c = new Caller();
         Rectangle r = new Rectangle(10, 7);
         Triangle t = new Triangle(10, 5);
         
         c.CallArea(r);
         c.CallArea(t);
         Console.ReadKey();
      }
   }
}

When the above code is compiled and executed, it produces the following result −

Rectangle class area:
Area: 70
Triangle class area:
Area: 25

Implementing Polymorphism with Interfaces

C# interfaces allow you to implement the same method signature in the multiple classes. Thus, you can achieve Polymorphism using the interface.

Example

In the following example, we are demonstrating polymorphism using an interface. The interface IAnimal is implemented by two different classes, Dog and Cat, each providing their own implementation of the MakeSound method.

using System;

public interface IAnimal
{
    void MakeSound();
}

public class Dog : IAnimal
{
    public void MakeSound()
    {
        Console.WriteLine("Dog barks: Woof Woof!");
    }
}

public class Cat : IAnimal
{
    public void MakeSound()
    {
        Console.WriteLine("Cat meows: Meow Meow!");
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        IAnimal animal;

        animal = new Dog();
        animal.MakeSound();

        animal = new Cat();
        animal.MakeSound();

        Console.ReadKey();
    }
}

When the above code is compiled and executed, it produces the following result −

Dog barks: Woof Woof!
Cat meows: Meow Meow!

Benefits of Using Polymorphism

  • Improves Code Reusability – Polymorphism allows different objects use the same interface, which helps avoid repeating code.
  • Enhances Maintainability – Polymorphism make it easier to add new features without changing existing code.
  • Supports Open/Closed Principle – Polymorphism allows you to extend the code with new features but prevents changes to existing code.
Advertisements