C# > Object-Oriented Programming (OOP) > Polymorphism > Runtime Polymorphism (Method Overriding)
Runtime Polymorphism with Method Overriding in C#
This example demonstrates runtime polymorphism (method overriding) in C#. We define a base class `Animal` with a virtual method `MakeSound`. Derived classes like `Dog` and `Cat` then override this method to provide their specific implementations. At runtime, the correct `MakeSound` method is called based on the actual object type, even if the object is referenced through a base class reference. This behavior allows for flexible and extensible code, making it easier to add new animal types without modifying existing code that uses the base `Animal` class.
Code Example
This code defines a base class `Animal` and two derived classes, `Dog` and `Cat`. The `MakeSound` method is declared as `virtual` in the base class, allowing derived classes to override its implementation using the `override` keyword. In the `Main` method, we create instances of each class and call the `MakeSound` method. Notice how the `animal2` and `animal3` variables, declared as type `Animal`, execute the overridden methods in their respective derived classes. This is runtime polymorphism in action.
using System;
public class Animal
{
public virtual void MakeSound()
{
Console.WriteLine("Generic animal sound");
}
}
public class Dog : Animal
{
public override void MakeSound()
{
Console.WriteLine("Woof!");
}
}
public class Cat : Animal
{
public override void MakeSound()
{
Console.WriteLine("Meow!");
}
}
public class Program
{
public static void Main(string[] args)
{
Animal animal1 = new Animal();
Animal animal2 = new Dog();
Animal animal3 = new Cat();
animal1.MakeSound(); // Output: Generic animal sound
animal2.MakeSound(); // Output: Woof!
animal3.MakeSound(); // Output: Meow!
}
}
Concepts Behind the Snippet
Real-Life Use Case
Consider a graphics rendering system. You might have a base class `Shape` with a `Draw` method. Derived classes like `Circle`, `Square`, and `Triangle` could override the `Draw` method to render their respective shapes. The rendering engine could then work with a collection of `Shape` objects, calling the `Draw` method on each one without needing to know the specific type of each shape. This allows for easily adding new shape types without modifying the core rendering engine.
Best Practices
Interview Tip
When asked about polymorphism, be prepared to explain the difference between compile-time polymorphism (method overloading) and runtime polymorphism (method overriding). Emphasize that method overriding is achieved through virtual methods and the `override` keyword, and that the decision of which method to execute is made at runtime based on the object's actual type.
When to Use Them
Use method overriding when you need to provide specialized behavior for a method in derived classes, while maintaining a common interface defined by the base class. This is particularly useful when you have a hierarchy of classes and need different implementations for a specific action based on the class type.
Memory Footprint
The memory footprint of using virtual methods and method overriding is slightly higher than using non-virtual methods. This is because the runtime needs to maintain a virtual method table (vtable) for each class with virtual methods. The vtable contains pointers to the actual method implementations for each virtual method in the class. However, the increased flexibility and extensibility provided by runtime polymorphism often outweighs the small increase in memory usage.
Alternatives
While method overriding is a common and powerful technique for achieving polymorphism, there are alternatives, such as:
Pros
Cons
FAQ
-
What is the difference between method overloading and method overriding?
Method overloading (compile-time polymorphism) involves defining multiple methods with the same name but different signatures (different parameters) within the same class. The compiler determines which method to call based on the arguments provided. Method overriding (runtime polymorphism) involves a subclass providing a specific implementation of a method that is already defined in its superclass. The runtime determines which method to call based on the actual type of the object. -
Why use the `virtual` keyword?
The `virtual` keyword allows a derived class to override the base class's implementation of a method. Without the `virtual` keyword, the derived class can only hide the base class's method, not override it. Hiding the method means that the base class implementation will be called if you use a variable declared as the base type, even if the object is a derived type. With overriding, the derived type implementation will always be called. -
What happens if I don't use the 'override' keyword when I'm trying to override a virtual method?
If you don't use the `override` keyword when defining a method in a derived class that has the same signature as a `virtual` method in the base class, you are hiding the base class's method, not overriding it. This means that if you call the method on an object of the derived class, the derived class's method will be called. However, if you call the method on a reference of the base class type that points to an object of the derived class, the base class's method will be called. Using the `override` keyword ensures that the derived class's implementation is always called, regardless of the reference type.