What is method overriding?
Method overriding is a concept in object-oriented programming that allows a subclass to provide a specific implementation for a method that is already defined in its superclass. When a subclass overrides a method from its superclass, it replaces the inherited implementation with its own implementation while keeping the method signature (name, return type, and parameter types) the same.
Key points about method overriding:
-
Inheritance Required: Method overriding is only applicable in inheritance hierarchies, where a subclass inherits methods from its superclass.
-
Method Signature: The overridden method in the subclass must have the exact same method signature (name, return type, and parameter types) as the method in the superclass.
-
Keyword: In most object-oriented languages like Java and C#, you use the override keyword to indicate that a method in the subclass is intended to 'override' a method in the superclass.
-
Polymorphism: Method overriding is a key aspect of polymorphism, allowing objects of the subclass to be treated as objects of the superclass while ensuring that the appropriate overridden method is called at runtime.
-
Access Modifiers: The access modifier of the overriding method in the subclass can't be more restrictive than the access modifier of the method in the superclass. It can be equally or more permissive (public > protected > internal/default).
-
Method Body: The overridden method in the subclass provides a new implementation specific to the subclass's behavior. It can't have a different number of parameters or different types of parameters compared to the method in the superclass.
-
base Keyword: In some languages (like C#), you can use the 'base' keyword to explicitly call the overridden method of the parent class from within the overridden method of the child class.
-
Runtime Polymorphism: When a method is called through a reference of the base class that actually points to an object of the derived class, the overridden method in the derived class is executed at runtime.
Method overriding allows for a more specialized behavior in subclasses, promoting code extensibility and reusability. It ensures that the most appropriate method implementation is used based on the actual type of the object, providing dynamic behavior and facilitating the principle of "substitutability" in object-oriented design.
Let's illustrate method overriding in C# using an example involving a base class Vehicle and two derived classes Car and Bicycle. We'll override a method called StartEngine() to provide specific implementations for each type of vehicle.
using System;
class Vehicle
{
public virtual void StartEngine()
{
Console.WriteLine("Starting the engine of a generic vehicle");
}
}
class Car : Vehicle
{
public override void StartEngine()
{
Console.WriteLine("Starting the engine of a car");
}
}
class Bicycle : Vehicle
{
public override void StartEngine()
{
Console.WriteLine("Bicycles don't have engines to start");
}
}
class Program
{
static void Main(string[] args)
{
Vehicle vehicle1 = new Vehicle();
Vehicle vehicle2 = new Car();
Vehicle vehicle3 = new Bicycle();
vehicle1.StartEngine();
vehicle2.StartEngine();
vehicle3.StartEngine();
}
}
In this example:
-
The 'Vehicle' class defines a 'virtual' method 'StartEngine()' with a default implementation for a generic vehicle.
-
The 'Car' class inherits from 'Vehicle' and overrides the 'StartEngine()' method with a specific implementation for starting a car's engine.
-
The 'Bicycle' class also inherits from Vehicle and overrides the 'StartEngine()' method to provide a message stating that bicycles don't have engines.
-
In the 'Main' method, instances of 'Vehicle', 'Car', and 'Bicycle' are created.
-
When the StartEngine()' method is called on each object, the appropriate overridden version is executed based on the actual type of the object.
When you run the program, you'll see the following output:
Starting the engine of a generic vehicle
Starting the engine of a car
Bicycles don't have engines to start
Despite using the same method name, the appropriate version of the method is executed based on the actual type of the object at runtime. This demonstrates method overriding and dynamic behavior, which is a key characteristic of polymorphism.