Method Overriding in C#
In object-oriented programming (OOP), method overriding is a basic idea that enables a derived class to offer a particular implementation for a method that is already specified in its base (parent) class. This procedure is also known as late binding or run-time polymorphism since it chooses which method implementation to employ based on the object’s actual type at run-time.
Key Concepts of Method Overriding
Purpose
In a subclass, method overriding is used to modify or specialise the behaviour of an inherited method. This allows for versatile and adaptable software architectures by letting objects of different classes to react to the same method call in different ways. If the implementation of the base class is not called, the derived class must make sure that its behaviour is consistent with that of the base class.
Keywords
To override a method in C#, use the virtual and override keywords.
virtual
: To indicate that derived classes can override a method, the virtual modifier must be explicitly specified with the base class method. C# differs significantly from languages like Java in that its methods are not by default virtual. One cannot designate a virtual method as private.
override
: With the override modifier, the derived class’s method that re-implements the base class’s virtual method needs to be explicitly specified. The overriding method must have the same signature as the base class virtual method, including the same name and parameter list. In the child class, overriding the method is not required.
new
Keyword (Method Hiding)
Method concealing, commonly known as shadowing, is supported in C# using the new keyword. A derived class method that hides the base class method is created when it employs the new keyword that has the same name as a base class method, whether or not it is virtual. The method call is resolved using the static type of the object reference rather than its actual runtime type in this instance, preventing polymorphic behaviour. For a method with the same name in a derived class, the compiler will raise an error and the method will act as though new were present if neither override nor new is supplied.
Polymorphic Behavior
The Common Language Runtime (CLR) makes sure that, even when an object is referenced by a base class type, the right method implementation (from the most derived class) is called at runtime when a method is overridden. This is a fundamental feature of polymorphism.
Calling Base Implementation
Even in an overriding method, you can use the base keyword to invoke the method’s implementation from the base class. Because of this, the derived class might enhance or supplement the original functionality instead of totally replacing it.
Abstract Methods
Non-abstract derived classes must use the override modifier to override abstract methods, which are declared in abstract classes but lack an implementation. Methods that are abstract are implicitly virtual.
Sealed Methods
In a derived class, an overridden method can be marked as sealed to stop it from being overridden in any more derived classes.
Differences from Method Overloading
Differentiating between method overloading and overriding is crucial:
Method Overloading: It is the process of defining several methods with the same name but distinct signatures (i.e., different numbers, types, or parameter order) within the same class (or across an inheritance tree). Different approaches to completing a same work are provided by overloading. Static (compile-time) polymorphism is what it is.
Method Overriding: Entails re-implementing a method in a derived class using the same name and signature as their base class counterpart. The method’s behaviour for the derived class is altered via overriding. It’s a type of run-time, dynamic polymorphism.
Feature | Method Overloading | Method Overriding |
Signature | Same name, different signature | Same name, same signature |
Location | Within the same class or across parent/child classes | Only in a child class |
Keywords Used | No separate keywords | virtual (base), override (derived) |
Polymorphism Type | Static (Compile-time) | Dynamic (Run-time) |
Purpose | Provide multiple behaviors for a method | Change/replace the behavior of a method |
Parent Permission | Not required | Explicit permission (virtual ) from parent required |
Code Example of Method Overriding
This sample illustrates polymorphism behaviour and shows how to use virtual and override keywords to override methods:
using System;
// Base class
public class Vehicle
{
protected int NumberOfWheels { get; set; } = 0;
public Vehicle() { }
// Declare the method as virtual to allow overriding in derived classes
public virtual void Display()
{
Console.WriteLine($"The number of wheels for the {nameof(Vehicle)} is {NumberOfWheels}");
}
}
// Derived class 1
public class Ducati : Vehicle
{
public Ducati()
{
NumberOfWheels = 2;
}
// Override the Display method to provide specific implementation for Ducati
public override void Display()
{
Console.WriteLine($"The number of wheels for the {nameof(Ducati)} is {NumberOfWheels}");
}
}
// Derived class 2
public class Lamborghini : Vehicle
{
public Lamborghini()
{
NumberOfWheels = 4;
}
// Override the Display method for Lamborghini
public override void Display()
{
Console.WriteLine($"The number of wheels for the {nameof(Lamborghini)} is {NumberOfWheels}");
// Optionally, call the base class implementation using 'base' keyword
// Console.Write(" (Base class info: ");
// base.Display();
// Console.WriteLine(")");
}
}
public class TestPolymorphism
{
public static void Main(string[] args)
{
Vehicle vehicle; // Declare a base class reference
// Assign an instance of the base class to the base class reference
vehicle = new Vehicle();
vehicle.Display();
Console.WriteLine("----------");
// Assign an instance of a derived class (Ducati) to the base class reference
vehicle = new Ducati();
vehicle.Display();
Console.WriteLine("----------");
// Assign another instance of a derived class (Lamborghini) to the base class reference
vehicle = new Lamborghini();
vehicle.Display();
Console.WriteLine("----------");
// Example using an array of base class type to demonstrate polymorphism
// Correctly initialize the array with a size that can hold the vehicles
Vehicle[] garage = new Vehicle[3]; // Array to hold 3 vehicles
// Assign instances to valid indices within the array
garage[0] = new Vehicle();
garage[1] = new Ducati();
garage[2] = new Lamborghini();
Console.WriteLine("\nGarage vehicles:");
foreach (Vehicle v in garage)
{
v.Display(); // At runtime, the correct overridden method is invoked for each object
}
}
}
Output
The number of wheels for the Vehicle is 0
----------
The number of wheels for the Ducati is 2
----------
The number of wheels for the Lamborghini is 4
----------
Garage vehicles:
The number of wheels for the Vehicle is 0
The number of wheels for the Ducati is 2
The number of wheels for the Lamborghini is 4
You can alo read C# Destructor: Your Guide To The Resource Management