Method Overriding - Customizing Inherited Behavior in C#
Vaibhav • September 10, 2025
In the previous article, we explored base and derived classes - how inheritance allows you to reuse and extend
behavior across related types. Now, we focus on a powerful feature that makes inheritance truly flexible:
method overriding. This article explains how derived classes can redefine methods from their
base class to provide specialized behavior, and how C# supports this through the virtual
and
override
keywords.
Method overriding is essential for implementing polymorphism - the ability to treat objects of different types through a common interface while allowing each type to behave differently. In this article, we’ll explore how overriding works, how to use it correctly, and how to avoid common mistakes when customizing inherited behavior.
What is Method Overriding?
Method overriding allows a derived class to provide its own implementation of a method that is defined in its base class. This is useful when the base class defines general behavior, and the derived class needs to specialize or replace that behavior.
public class Animal
{
public virtual void Speak()
{
Console.WriteLine("Animal makes a sound");
}
}
public class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("Dog says woof");
}
}
In this example, Speak()
is defined in the base class Animal
and marked as
virtual
. The derived class Dog
overrides it using the override
keyword to
provide a dog-specific implementation.
Animal a = new Dog();
a.Speak(); // Output: Dog says woof
Even though a
is declared as Animal
, the overridden method in Dog
is
called. This is polymorphism in action.
To override a method, the base method must be marked virtual
,
abstract
, or override
. The derived method must use the override
keyword.
Using virtual
and override
The virtual
keyword in the base class signals that a method can be overridden. The
override
keyword in the derived class replaces the base implementation.
public class Vehicle
{
public virtual void Start()
{
Console.WriteLine("Vehicle starting");
}
}
public class Car : Vehicle
{
public override void Start()
{
Console.WriteLine("Car engine starting");
}
}
This pattern allows derived classes to customize behavior while maintaining a consistent interface.
Calling the Base Method
Sometimes you want to extend the base method rather than replace it entirely. You can use the base
keyword to call the base implementation from the overridden method.
public class Bird : Animal
{
public override void Speak()
{
base.Speak(); // Calls Animal.Speak()
Console.WriteLine("Bird chirps");
}
}
This allows you to build on the base behavior while adding new functionality.
Overriding Properties
You can also override properties in derived classes. This is useful when the property logic needs to change.
public class Shape
{
public virtual double Area => 0;
}
public class Circle : Shape
{
public double Radius { get; set; }
public override double Area => Math.PI * Radius * Radius;
}
The Area
property is overridden in Circle
to provide a meaningful calculation. This
supports polymorphic access to properties.
Overriding ToString()
One of the most commonly overridden methods is ToString()
, which returns a string representation of
an object. The default implementation returns the type name, but you can override it to provide more useful
output.
public class Product
{
public string Name { get; set; }
public decimal Price { get; set; }
public override string ToString()
{
return $"{Name} - ${Price}";
}
}
Now, printing a Product
object gives a readable summary:
Product p = new Product { Name = "Laptop", Price = 999.99m };
Console.WriteLine(p); // Output: Laptop - $999.99
Preventing Overriding with sealed
If you want to prevent further overriding of a method, you can mark it as sealed
. This is useful
when you want to lock down behavior in a derived class.
public class Printer
{
public virtual void Print() => Console.WriteLine("Printing...");
}
public class SecurePrinter : Printer
{
public sealed override void Print() => Console.WriteLine("Secure print");
}
public class AdvancedPrinter : SecurePrinter
{
// ❌ Cannot override Print() here
}
The Print()
method in SecurePrinter
is sealed, so AdvancedPrinter
cannot
override it. This helps enforce design constraints.
Abstract Methods and Overriding
An abstract
method has no implementation in the base class and must be overridden in derived
classes. This is useful when the base class defines a contract but leaves the implementation to subclasses.
public abstract class Shape
{
public abstract double Area();
}
public class Rectangle : Shape
{
public double Width { get; set; }
public double Height { get; set; }
public override double Area() => Width * Height;
}
The Shape
class defines an abstract method Area()
. Each derived class must provide its
own implementation.
Abstract methods can only exist in abstract classes. You cannot instantiate an abstract class directly.
Common Mistakes to Avoid
Method overriding is powerful, but it can lead to bugs if misused. Avoid these common mistakes:
- Forgetting to mark the base method as
virtual
. - Using
new
instead ofoverride
(covered in the next article). - Overriding methods without understanding base behavior.
- Breaking polymorphism by calling methods directly on derived types.
Always design base methods with overriding in mind. Document their purpose and expected behavior clearly.
Summary
Method overriding allows derived classes to customize behavior defined in base classes. It supports
polymorphism, promotes extensibility, and helps model real-world variations in behavior. In C#, overriding is
enabled through the virtual
and override
keywords, and can be applied to methods,
properties, and indexers.
We explored how to override methods, how to call base implementations, how to use abstract and sealed modifiers, and how to avoid common mistakes. We also saw how overriding enables polymorphic behavior and improves code reuse.
As you continue building class hierarchies, use method overriding to specialize behavior while maintaining a
consistent interface. In the next article, we’ll explore Method Hiding - how to redefine base
methods without overriding them, and when to use the new
keyword.