C# tutorials > Core C# Fundamentals > Object-Oriented Programming (OOP) > What is method overloading and method overriding (using `virtual` and `override`)?

What is method overloading and method overriding (using `virtual` and `override`)?

This tutorial explains method overloading and overriding in C#, two fundamental concepts in Object-Oriented Programming (OOP). Method overloading allows you to define multiple methods with the same name but different signatures within the same class. Method overriding, on the other hand, allows a derived class to provide a specific implementation of a method that is already provided by its base class. We'll explore these concepts with code examples and explanations.

Method Overloading: Introduction

Method overloading enables you to create multiple methods with the same name within the same class, as long as they have different parameter lists (different number of parameters, different types of parameters, or different order of parameters). The compiler determines which overloaded method to call based on the arguments passed during the method invocation.

Method Overloading: Code Example

In this example, the `Calculator` class has multiple `Add` methods. Each `Add` method takes different types or number of parameters. When you call `Add`, the compiler selects the appropriate method based on the arguments you provide.

public class Calculator
{
    public int Add(int a, int b)
    {
        return a + b;
    }

    public double Add(double a, double b)
    {
        return a + b;
    }

    public int Add(int a, int b, int c)
    {
        return a + b + c;
    }

    public string Add(string a, string b)
    {
        return a + b;
    }
}

Method Overloading: Usage Example

This code demonstrates how the different overloaded `Add` methods are called based on the provided arguments.

Calculator calc = new Calculator();
int sum1 = calc.Add(2, 3); // Calls Add(int a, int b)
double sum2 = calc.Add(2.5, 3.7); // Calls Add(double a, double b)
int sum3 = calc.Add(1, 2, 3); // Calls Add(int a, int b, int c)
string sum4 = calc.Add("Hello, ", "World!"); // Calls Add(string a, string b)

Console.WriteLine($"Sum1: {sum1}");
Console.WriteLine($"Sum2: {sum2}");
Console.WriteLine($"Sum3: {sum3}");
Console.WriteLine($"Sum4: {sum4}");

Method Overriding: Introduction (Virtual and Override)

Method overriding allows a derived class to provide a specific implementation for a method that is already defined in its base class. To enable method overriding, the base class method must be declared as `virtual`. The derived class then uses the `override` keyword to provide its own implementation.

Method Overriding: Code Example

Here, the `Animal` class has a `virtual` method called `MakeSound`. The `Dog` and `Cat` classes inherit from `Animal` and `override` the `MakeSound` method to provide their specific sound implementations.

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!");
    }
}

Method Overriding: Usage Example

This code demonstrates how the overridden methods are called based on the actual type of the object at runtime. Even though `animal2` and `animal3` are declared as `Animal`, their `MakeSound` methods behave according to their specific derived classes (`Dog` and `Cat`). This is polymorphism in action.

Animal animal1 = new Animal();
animal1.MakeSound(); // Output: Generic animal sound

Animal animal2 = new Dog();
animal2.MakeSound(); // Output: Woof!

Animal animal3 = new Cat();
animal3.MakeSound(); // Output: Meow!

Dog dog = new Dog();
dog.MakeSound(); // Output: Woof!

Concepts Behind the Snippet

Method Overloading: The key concept is providing multiple methods with the same name but different signatures. This allows for more flexible and readable code.

Method Overriding: The key concept is polymorphism. It allows a base class reference to execute the derived class's implementation of a method. The `virtual` keyword in the base class indicates that the method can be overridden, and the `override` keyword in the derived class signifies that the method is indeed overriding the base class method. If you don't use virtual/override you'll hide the base member which is another concept but totally different of overriding.

Real-Life Use Case

Consider a `Shape` class with a `CalculateArea()` method. Derived classes like `Circle`, `Rectangle`, and `Triangle` can override `CalculateArea()` to provide their specific area calculation logic. Method overloading can be used for a `Draw` method to accept different number of parameters or different types of graphic drawing libraries.

Best Practices

  • Use method overloading to provide convenience methods with varying levels of detail.
  • Use method overriding to implement polymorphic behavior in inheritance hierarchies.
  • Always document overloaded and overridden methods clearly.
  • When overriding methods, ensure that the derived class's implementation adheres to the contract defined by the base class.

Interview Tip

Be prepared to explain the difference between method overloading and method overriding. Know when to use each technique and be ready to provide examples. A common follow-up question is about method hiding (using `new` keyword), which is different from overriding.

When to use them

Method Overloading: Use method overloading when you want to provide multiple ways to call a method with varying input parameters.

Method Overriding: Use method overriding when you want to provide specialized behavior for a method in a derived class that is different from the base class implementation. The base class has the default behavior and derived class can change it to follow the Liskov Substitution principle.

Memory footprint

Method overloading doesn't directly affect the memory footprint in a significant way. Each overloaded method has its own code and metadata stored in memory. Method overriding, when combined with polymorphism, introduces a slight overhead because the runtime needs to determine the correct method to call at runtime. This is typically done through a vtable (virtual table) lookup, which adds a very small memory overhead per class with virtual methods. The memory footprint differences are almost negligible in the most cases.

Alternatives

Method Overloading: Instead of overloading, you could potentially use optional parameters or parameter objects. However, overloading often leads to cleaner and more readable code.

Method Overriding: If overriding is not possible (e.g., if you can't modify the base class), you might consider using composition or extension methods to achieve similar behavior.

Pros of Method Overloading and Overriding

Method Overloading: Improved code readability, flexibility in method usage.

Method Overriding: Polymorphism, code reusability, extensibility, adherence to the Open/Closed Principle.

Cons of Method Overloading and Overriding

Method Overloading: Can lead to confusion if not used carefully, potential for code duplication if overloaded methods share significant logic.

Method Overriding: Can make inheritance hierarchies more complex, requires careful design to avoid unexpected behavior.

FAQ

  • What happens if I don't use the `override` keyword when I intend to override a virtual method?

    The compiler will issue a warning (CS0108) indicating that you are hiding the base class member. The derived class method will not actually override the base class method; instead, it will create a new method with the same name that hides the base class method. You would need to use the `new` keyword to explicitly hide the base class member without compiler warning.
  • Can I override a method that is not declared as `virtual`?

    No. Only methods declared as `virtual`, `abstract`, or `override` can be overridden in a derived class.
  • Can I overload method with different return type?

    No. Method overloading in C# requires the methods to have different parameter lists (different number, types, or order of parameters). The return type is not part of the method signature and therefore cannot be used to differentiate overloaded methods. You will get a compiler error if you try to overload methods based solely on return type.