Understanding C# Polymorphism

Polymorphism in C# is a key concept of object-oriented programming (OOP) that allows methods or objects to take multiple forms. It enables a derived class to override the behavior of a base class, allowing a consistent interface while maintaining flexibility in how behavior is implemented.

Key Topics

What is Polymorphism?

Polymorphism allows objects of different types to be treated as objects of a common base type. It is achieved primarily through method overriding and the use of virtual and abstract methods.

Example: Basic Polymorphism

public class Animal
{
    public virtual void Speak()
    {
        Console.WriteLine("The animal makes a sound.");
    }
}

public class Dog : Animal
{
    public override void Speak()
    {
        Console.WriteLine("The dog barks.");
    }
}

public class Cat : Animal
{
    public override void Speak()
    {
        Console.WriteLine("The cat meows.");
    }
}

class Program
{
    static void Main(string[] args)
    {
        // Polymorphism: base class reference to derived objects
        Animal myDog = new Dog();
        Animal myCat = new Cat();

        // Calls the overridden methods
        myDog.Speak();  // Output: The dog barks.
        myCat.Speak();  // Output: The cat meows.
    }
}

Output:

The dog barks.
The cat meows.
                        

Explanation: Polymorphism allows us to use a base class reference (in this case, Animal) to call methods on derived class objects (Dog and Cat). Each derived class overrides the Speak() method to provide its specific behavior.

Method Overriding

Method overriding in C# allows a derived class to provide a specific implementation of a method that is already defined in its base class. To override a method, the base method must be marked with the virtual keyword, and the derived class method must be marked with the override keyword.

Example: Method Overriding

public class Vehicle
{
    // Virtual method in base class
    public virtual void StartEngine()
    {
        Console.WriteLine("Starting engine...");
    }
}

public class Car : Vehicle
{
    // Override method in derived class
    public override void StartEngine()
    {
        Console.WriteLine("Starting car engine...");
    }
}

public class Motorcycle : Vehicle
{
    // Override method in derived class
    public override void StartEngine()
    {
        Console.WriteLine("Starting motorcycle engine...");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Vehicle car = new Car();
        Vehicle motorcycle = new Motorcycle();

        // Calls the overridden method
        car.StartEngine();          // Output: Starting car engine...
        motorcycle.StartEngine();    // Output: Starting motorcycle engine...
    }
}

Output:

Starting car engine...
Starting motorcycle engine...
                        

Explanation: Method overriding allows derived classes (Car and Motorcycle) to provide their own implementations of the StartEngine() method, which is originally defined in the base class Vehicle.

Virtual Methods

A virtual method in a base class provides the ability for derived classes to override the method's implementation. Virtual methods are the foundation of polymorphism in C#.

Example: Using Virtual Methods

public class Employee
{
    // Virtual method
    public virtual void Work()
    {
        Console.WriteLine("Employee is working...");
    }
}

public class Manager : Employee
{
    // Override the virtual method
    public override void Work()
    {
        Console.WriteLine("Manager is overseeing the project...");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Employee employee = new Employee();
        Employee manager = new Manager();

        // Call the Work method
        employee.Work();    // Output: Employee is working...
        manager.Work();     // Output: Manager is overseeing the project...
    }
}

Output:

Employee is working...
Manager is overseeing the project...
                        

Explanation: In this example, the base class Employee defines a virtual method Work(). The derived class Manager overrides this method to provide specific behavior. The base class reference can call the overridden method in the derived class.

Abstract Classes and Methods

Abstract classes in C# are base classes that cannot be instantiated and often contain abstract methods, which are methods without a body. Derived classes are required to provide implementations for all abstract methods.

Example: Using Abstract Classes and Methods

public abstract class Shape
{
    // Abstract method (no implementation)
    public abstract double CalculateArea();
}

public class Circle : Shape
{
    public double Radius { get; set; }

    // Implement the abstract method
    public override double CalculateArea()
    {
        return Math.PI * Radius * Radius;
    }
}

class Program
{
    static void Main(string[] args)
    {
        // Create a new Circle object
        Circle circle = new Circle { Radius = 5 };

        // Calculate and display the area
        Console.WriteLine($"Circle Area: {circle.CalculateArea()}");
    }
}

Output:

Circle Area: 78.53981633974483
                        

Explanation: The abstract class Shape contains the abstract method CalculateArea(), which is implemented in the derived class Circle. The abstract method enforces that any class inheriting from Shape must provide its own implementation of CalculateArea().

Polymorphism in Action

Polymorphism can be seen in action when you use a base class reference to invoke overridden methods in derived class objects. This provides flexibility while keeping the code maintainable.

Example: Polymorphism in Action

public class Instrument
{
    public virtual void Play()
    {
        Console.WriteLine("Playing an instrument...");
    }
}

public class Piano : Instrument
{
    public override void Play()
    {
        Console.WriteLine("Playing the piano...");
    }
}

public class Guitar : Instrument
{
    public override void Play()
    {
        Console.WriteLine("Playing the guitar...");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Instrument piano = new Piano();
        Instrument guitar = new Guitar();

        piano.Play();   // Output: Playing the piano...
        guitar.Play();  // Output: Playing the guitar...
    }
}

Output:

Playing the piano...
Playing the guitar...
                        

Explanation: In this example, the base class Instrument defines a Play() method. The derived classes Piano and Guitar override this method. Using polymorphism, we invoke the correct implementation of the Play() method based on the object type at runtime.

Key Takeaways

  • Polymorphism allows objects of different derived types to be treated as objects of a common base type.
  • Method overriding enables derived classes to provide their own implementation of base class methods.
  • Virtual methods allow derived classes to override the behavior of base class methods.
  • Abstract classes define abstract methods that must be implemented by derived classes.