.NET Method Overriding
Method overriding is a fundamental concept in object-oriented programming that allows a derived class to provide a specific implementation of a method that is already defined in its base class. This is one of the key mechanisms that enable polymorphism in C# and .NET.
Introduction to Method Overriding
In object-oriented programming, classes can inherit properties and behaviors from other classes. Sometimes, you need a derived class to change or extend the behavior defined in the base class. Method overriding enables you to redefine a method in a derived class that has already been defined in the base class.
The key points about method overriding include:
- It implements runtime polymorphism
- It requires inheritance (a parent-child class relationship)
- The method in the base class must be declared as
virtual
- The method in the derived class must use the
override
keyword
Method Overriding vs Method Hiding vs Method Overloading
Before diving deeper, let's clarify the differences between these similar concepts:
Concept | Description |
---|---|
Method Overriding | Redefines a method in a derived class that is already defined in the base class (using virtual and override keywords) |
Method Hiding | Similar to overriding, but uses the new keyword instead of override to hide the base implementation |
Method Overloading | Multiple methods with the same name but different parameters in the same class |
How Method Overriding Works in C#
To override a method in C#:
- The base class method must be declared with the
virtual
keyword - The derived class method must use the
override
keyword - Both methods must have the same name, return type, and parameters
Let's look at a basic example:
public class Shape
{
public virtual void Draw()
{
Console.WriteLine("Drawing a shape");
}
}
public class Circle : Shape
{
public override void Draw()
{
Console.WriteLine("Drawing a circle");
}
}
public class Rectangle : Shape
{
public override void Draw()
{
Console.WriteLine("Drawing a rectangle");
}
}
When we use these classes:
// Example usage
Shape shape = new Shape();
shape.Draw(); // Output: "Drawing a shape"
Shape circle = new Circle();
circle.Draw(); // Output: "Drawing a circle"
Shape rectangle = new Rectangle();
rectangle.Draw(); // Output: "Drawing a rectangle"
The virtual
Keyword
The virtual
keyword in the base class indicates that a method can be overridden in derived classes. Without this keyword, derived classes cannot override the method.
The override
Keyword
The override
keyword in the derived class indicates that this method provides a new implementation of a virtual method defined in the base class.
Accessing the Base Class Method
Sometimes, you might want to extend the base class functionality rather than completely replacing it. The base
keyword allows you to call the base class method from the derived class:
public class Circle : Shape
{
public override void Draw()
{
base.Draw(); // Call the base class implementation first
Console.WriteLine("Drawing a circle with radius");
}
}
Output when calling circle.Draw()
:
Drawing a shape
Drawing a circle with radius
Abstract Methods and Method Overriding
Abstract methods are closely related to method overriding. An abstract method has no implementation in the base class and must be overridden in derived classes.
public abstract class Shape
{
public abstract void Draw(); // No implementation, must be overridden
public void DisplayArea()
{
Console.WriteLine("Displaying area calculation");
}
}
public class Circle : Shape
{
public override void Draw() // Must implement this method
{
Console.WriteLine("Drawing a circle");
}
}
Real-World Example: Banking System
Let's explore a more practical example of method overriding in a banking system:
public class BankAccount
{
public string AccountNumber { get; set; }
protected decimal balance;
public BankAccount(string accountNumber, decimal initialBalance)
{
AccountNumber = accountNumber;
balance = initialBalance;
}
public virtual string GetAccountInfo()
{
return $"Account Number: {AccountNumber}, Balance: ${balance}";
}
public virtual void Deposit(decimal amount)
{
if (amount > 0)
{
balance += amount;
Console.WriteLine($"Deposited ${amount}. New balance: ${balance}");
}
}
public virtual bool Withdraw(decimal amount)
{
if (amount <= balance && amount > 0)
{
balance -= amount;
Console.WriteLine($"Withdrew ${amount}. New balance: ${balance}");
return true;
}
Console.WriteLine("Insufficient funds or invalid amount");
return false;
}
}
public class SavingsAccount : BankAccount
{
public decimal InterestRate { get; private set; }
public SavingsAccount(string accountNumber, decimal initialBalance, decimal interestRate)
: base(accountNumber, initialBalance)
{
InterestRate = interestRate;
}
public override string GetAccountInfo()
{
return $"{base.GetAccountInfo()}, Interest Rate: {InterestRate:P}";
}
public void AddInterest()
{
decimal interest = balance * InterestRate;
balance += interest;
Console.WriteLine($"Added ${interest} interest. New balance: ${balance}");
}
}
public class CheckingAccount : BankAccount
{
public decimal OverdraftLimit { get; private set; }
public CheckingAccount(string accountNumber, decimal initialBalance, decimal overdraftLimit)
: base(accountNumber, initialBalance)
{
OverdraftLimit = overdraftLimit;
}
public override string GetAccountInfo()
{
return $"{base.GetAccountInfo()}, Overdraft Limit: ${OverdraftLimit}";
}
public override bool Withdraw(decimal amount)
{
if (amount > 0 && amount <= (balance + OverdraftLimit))
{
balance -= amount;
Console.WriteLine($"Withdrew ${amount}. New balance: ${balance}");
if (balance < 0)
{
Console.WriteLine($"Warning: Account is overdrawn by ${Math.Abs(balance)}");
}
return true;
}
Console.WriteLine("Insufficient funds (exceeds overdraft limit) or invalid amount");
return false;
}
}
Using these classes:
// Create different account types
SavingsAccount savings = new SavingsAccount("SA-1234", 1000, 0.05m);
CheckingAccount checking = new CheckingAccount("CA-5678", 500, 200);
// Test method overriding with polymorphism
BankAccount account1 = savings;
BankAccount account2 = checking;
Console.WriteLine(account1.GetAccountInfo());
// Output: Account Number: SA-1234, Balance: $1000, Interest Rate: 5.00%
Console.WriteLine(account2.GetAccountInfo());
// Output: Account Number: CA-5678, Balance: $500, Overdraft Limit: $200
// Test the overridden Withdraw method
account1.Withdraw(200); // Uses base implementation
// Output: Withdrew $200. New balance: $800
account2.Withdraw(600); // Uses overridden implementation
// Output: Withdrew $600. New balance: $-100
// Warning: Account is overdrawn by $100
Best Practices for Method Overriding
- Clear Purpose: Only override methods when you need to change or extend behavior
- Maintain Contracts: The overridden method should follow the same contract (expected behavior) as the base method
- Use
base
: Call the base implementation when extending functionality rather than completely replacing it - Avoid Deep Hierarchies: Excessive inheritance can make code hard to understand
- Documentation: Clearly document the differences in behavior when overriding methods
When to Use Method Overriding
Method overriding is appropriate in the following scenarios:
- When a derived class needs to modify behavior inherited from the base class
- When implementing polymorphic behavior
- When working with an abstract class that requires implementation of abstract methods
- When extending functionality of a base class method
Common Pitfalls and Solutions
1. Forgetting the virtual
Keyword
If you forget to mark a method as virtual
in the base class:
public class Base
{
public void Method() // Missing 'virtual' keyword
{
Console.WriteLine("Base Method");
}
}
public class Derived : Base
{
public override void Method() // Compilation error
{
Console.WriteLine("Derived Method");
}
}
This will cause a compilation error because the method in the base class is not marked as virtual
.
2. Forgetting the override
Keyword
If you forget the override
keyword, C# will interpret it as method hiding:
public class Base
{
public virtual void Method()
{
Console.WriteLine("Base Method");
}
}
public class Derived : Base
{
public void Method() // Missing 'override' keyword
{
Console.WriteLine("Derived Method");
}
}
The compiler will warn you that this hides the base method, and you should use either new
or override
.
Summary
Method overriding is a powerful feature in .NET that allows derived classes to provide specific implementations of methods defined in the base class. Key points to remember:
- Use the
virtual
keyword in the base class to allow overriding - Use the
override
keyword in the derived class to override a method - Method overriding enables polymorphism, a core OOP principle
- The
base
keyword allows you to call the base class implementation - Abstract methods must be overridden in non-abstract derived classes
- Method overriding is different from method hiding and method overloading
By mastering method overriding, you'll be able to write more flexible and maintainable object-oriented code in C# and .NET.
Exercises
-
Create a
Vehicle
base class with avirtual
method calledCalculateFuelEfficiency()
. Then createCar
andMotorcycle
derived classes that override this method with their own implementations. -
Extend the banking example above by adding a
BusinessAccount
class that overrides theWithdraw
method to include a transaction fee. -
Create an abstract
Employee
class with an abstractCalculatePay()
method, then implement concrete derived classes for different employee types.
Additional Resources
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)