Skip to main content

42. Override vs Overload in C#

Level: Intermediate
Goal: Understand the difference between two ways to reuse method names - compile-time vs runtime.

Overload (compile-time): Same name, different parameters

void Calculate(int a, int b) { }
void Calculate(double a, double b) { }
void Calculate(string a) { }

Override (runtime): Same name, inherits from parent

class Person { virtual void GetGrade() { } }
class Student : Person { override void GetGrade() { } }

Most confused OOP concept.

ℹ️ What You'll Learn
  • Method overloading - same name, different parameters
  • Method overriding - parent/child, same signature
  • Compile-time vs runtime polymorphism
  • Virtual dispatch - how C# picks which method to run
  • When to use overloading (convenience methods)
  • When to use overriding (true polymorphism)
  • Common mistakes and design patterns
  • Interview-ready explanations

Override vs Overload Reference

OverloadingOverriding
LocationSame classParent ? Child class
Method nameSameSame
Parameters? Different? Same
Return typeCan differSame (or covariant)
KeywordsNonevirtual + override
Base classN/AMust be virtual
Resolved atCompile-timeRuntime
PolymorphismAd-hoc (static)True (dynamic/virtual)
ExampleFunc(int), Func(string)virtual void Func(), override void Func()
Use caseMultiple input typesDifferent behavior per class

Method Overloading - Same Name, Different Parameters

Same class. Same method name. Different parameter signatures.

public class ReportService
{
// Overload 1 - name only
public void GenerateReport(string studentName)
{
Console.WriteLine($"Report for: {studentName}");
}

// Overload 2 - name + class
public void GenerateReport(string studentName, string className)
{
Console.WriteLine($"Report: {studentName} | Class: {className}");
}

// Overload 3 - name + class + marks array
public void GenerateReport(string studentName, string className, int[] marks)
{
double avg = marks.Average();
Console.WriteLine($"Report: {studentName} | {className} | Avg: {avg:F1}");
}

// Overload 4 - Student object
public void GenerateReport(Student student)
{
Console.WriteLine($"Report: {student.Name} | {student.Percentage:F1}%");
}

// ? Return type ALONE cannot distinguish overloads
// [X] This is NOT valid overloading:
// public string GenerateReport(string name)
// {
// return name; // error - same params as #1
// }
}

// Compiler picks correct overload based on arguments
var svc = new ReportService();
svc.GenerateReport("Sahasra"); // calls overload 1
svc.GenerateReport("Sahasra", "10th"); // calls overload 2
svc.GenerateReport("Sahasra", "10th", new[]{82,91,78}); // calls overload 3
svc.GenerateReport(student); // calls overload 4

Method Overriding - Replace Base Class Behavior

Different classes (parent/child). Same method name AND parameters. Override behavior.

public class Person
{
public string Name { get; set; } = "";

// virtual - CAN be overridden
public virtual string GetRole()
{
return "Person";
}

public virtual void PrintSummary()
{
Console.WriteLine($"[Person] {Name}");
}
}

public class Student : Person
{
public double Percentage { get; set; }

// override - REPLACES parent method
public override string GetRole() => "Student";

public override void PrintSummary()
=> Console.WriteLine($"[Student] {Name} | {Percentage:F1}%");
}

public class Teacher : Person
{
public string Subject { get; set; } = "";

public override string GetRole() => "Teacher";

public override void PrintSummary()
=> Console.WriteLine($"[Teacher] {Name} | {Subject}");
}

// Runtime dispatches to correct override
List<Person> members = new()
{
new Student { Name="Sahasra", Percentage=87.5 },
new Teacher { Name="Dr. Mehta", Subject="Maths" },
};

foreach (var m in members)
m.PrintSummary(); // each gets its own version
// [Student] Sahasra | 87.5%
// [Teacher] Dr. Mehta | Maths

Side-by-Side Comparison

OverloadingOverriding
WhereSame classParent ? Child
Method nameSameSame
ParametersDifferentSame
Return typeCan differSame (or covariant)
KeywordsNonevirtual + override
Resolved atCompile timeRuntime
PurposeMultiple ways to callReplace parent behavior
PolymorphismAd-hocRuntime

Common Mistakes

? Changing parameters - thinking it-s overriding (it-s overloading):

public class Person
{
public virtual void DisplayInfo()
=> Console.WriteLine("Person info");
}

public class Student : Person
{
// Wrong - different parameters, not overriding
public override void DisplayInfo(string className) // Added param
=> Console.WriteLine($"Student in {className}");
}

var people = new List<Person> { new Student() };
foreach (var p in people)
p.DisplayInfo(); // Calls Person.DisplayInfo, not Student

? Match base signature exactly:

public class Student : Person
{
public override void DisplayInfo() // ? Same signature
=> Console.WriteLine("Student info");
}

foreach (var p in people)
p.DisplayInfo(); // Calls Student.DisplayInfo

? Using override without virtual in base (compile error):

public class Person
{
public void GetRole() // NOT virtual
=> Console.WriteLine("Person");
}

public class Student : Person
{
public override void GetRole() // Error - base not virtual
=> Console.WriteLine("Student");
}

? Add virtual to base method:

public class Person
{
public virtual void GetRole() // ? virtual
=> Console.WriteLine("Person");
}

public class Student : Person
{
public override void GetRole() // ? OK
=> Console.WriteLine("Student");
}

? Confusing overload and override:

public class ReportService
{
public void Generate(string name) // Overload 1
=> Console.WriteLine(name);

public void Generate(string name, int days) // Overload 2
=> Console.WriteLine($"{name} for {days} days");
}

// vs.

public class BaseReport
{
public virtual void Generate()
=> Console.WriteLine("Report");
}

public class StudentReport : BaseReport
{
public override void Generate() // Override - replaces parent
=> Console.WriteLine("Student Report");
}

? Use overloading for convenience methods in same class:

public class StudentProcessor
{
// Overload 1 - basic
public void Process(Student student)
=> Console.WriteLine(student.Name);

// Overload 2 - with details
public void Process(Student student, bool detailed)
{
Process(student); // reuse first overload
if (detailed) Console.WriteLine(student.Percentage);
}
}

? Mixing overload and override (confusing):

public class Person
{
public virtual void Print()
=> Console.WriteLine("Person");
}

public class Student : Person
{
public override void Print() // Override base
=> Console.WriteLine("Student");

public void Print(bool detailed) // Overload override
{
Print(); // Calls override
if (detailed) Console.WriteLine("Details");
}
}

? Clarify intent - document which is which:

public class Student : Person
{
// Override parent-s method (virtual dispatch)
public override void Print()
=> Console.WriteLine("Student");

// Convenience overload (compile-time)
public void PrintDetailed()
=> Print();
}

Best Practices

  1. Use overloading for convenience methods - Multiple ways to call same logic
  2. Use overriding for polymorphism - Replace parent behavior in subclass
  3. Mark methods virtual intentionally - Not every method should be overridable
  4. Keep overload signatures distinct - Compiler must disambiguate easily
  5. Don-t overload with similar parameter types - Confusing: Func(int) vs Func(double)
  6. Use same parameter names in overrides - IDE hints show consistent names
  7. Document virtual methods - Explain what subclasses should do
  8. Test polymorphism in collections - Override works through base reference
  9. Avoid using new keyword - Use override for inheritance
  10. Consider sealed classes if not extensible - Prevent accidental overrides
  11. Use abstract methods for must-override - Force derived classes to implement
  12. Keep method complexity reasonable - Complex methods hard to override correctly

When You'll Use This in SMS

SMS uses both overloading and overriding:

// Overloading - same name, different params
public class StudentService
{
public Student GetStudent(int id) => _repo.GetById(id);
public Student GetStudent(string rollNumber) => _repo.GetByRoll(rollNumber);
}

// Overriding - replace base method
public class Student : BaseEntity
{
public override void Validate()
{
if (string.IsNullOrWhiteSpace(Name)) throw new Exception("Name required");
}
}

ℹ️ Video Tutorial

Override vs overload explained: same name different params (overload), replace base behavior (override). Video coming soon. Subscribe to NexCoding YouTube for updates.


🎯 Q1: What-s the difference between overloading and overriding?

Overloading: Same class, same name, DIFFERENT parameters. Compile-time.

Overriding: Parent?Child class, same name, SAME parameters. Runtime, requires virtual + override.

// Overloading - compile-time, same class
public class Calculator
{
public int Add(int a, int b) => a + b; // Overload 1
public double Add(double a, double b) => a + b; // Overload 2
}

// Overriding - runtime, inheritance
public class Person
{
public virtual void GetRole() => "Person";
}

public class Student : Person
{
public override void GetRole() => "Student"; // Replaces Person version
}

Rule: Overloading for convenience in same class. Overriding for polymorphism in inheritance.

🎯 Q2: Can I override a non-virtual method?

No. Only virtual or abstract methods can be overridden. Compiler error otherwise.

public class Person
{
public void GetRole() { } // NOT virtual
}

public class Student : Person
{
public override void GetRole() { } // Error
}

Solution: Either make base virtual, or use new (method hiding):

public class Person
{
public virtual void GetRole() { } // ? virtual
}

public class Student : Person
{
public override void GetRole() { } // ? OK
}

// OR use new (not recommended)
public class Student : Person
{
public new void GetRole() { } // Hiding, not overriding
}

virtual signals "designed for override." Never override non-virtual method.

🎯 Q3: Is overloading compile-time or runtime?

Compile-time. Compiler picks the overload based on parameter types AT COMPILE TIME.

public void Process(int x) => Console.WriteLine("int");
public void Process(string s) => Console.WriteLine("string");

Process(5); // Compiler sees int ? calls Process(int)
Process("hello"); // Compiler sees string ? calls Process(string)

// Compiler KNOWS which overload to use before runtime

Overriding = runtime. Runtime picks the method based on ACTUAL OBJECT TYPE.

Person p = new Student();
p.GetRole(); // Runtime checks: actual type is Student ? calls Student.GetRole()

Overload = static polymorphism (compile-time). Override = dynamic polymorphism (runtime).

🎯 Q4: Can I overload and override the same method?

Yes, valid but confusing. You can override parent-s method AND overload it.

public class Person
{
public virtual void Print() => Console.WriteLine("Person");
}

public class Student : Person
{
public override void Print() // Override parent
=> Console.WriteLine("Student");

public void Print(string extra) // Overload override
{
Print(); // Calls override above
Console.WriteLine(extra);
}
}

var s = new Student();
s.Print(); // Student.Print() ? override
s.Print("Detailed"); // Student.Print(string) ? overload

Person p = new Student();
p.Print(); // Student.Print() - override works through base reference
// p.Print("x"); // Error - overload not accessible through Person reference

Technically works but confusing. Keep separate: override parent, overload in same class.

🎯 Q5: When should I override a method?

Override when: You want different behavior in subclass AND want it called polymorphically.

// Override - PrintSummary changes per type
public class Person
{
public virtual void PrintSummary()
=> Console.WriteLine($"Person: {Name}");
}

public class Student : Person
{
public override void PrintSummary()
=> Console.WriteLine($"Student: {Name} | {Percentage:F1}%");
}

// Works in collections
foreach (Person p in new Person[] { new Student(), new Teacher() })
p.PrintSummary(); // Each calls correct version

Don-t override when: Behavior is identical or shouldn-t change per type.

Override = polymorphism. Only if behavior differs meaningfully.

🎯 Q6: What-s the contract for overriding?

1. Signature must match exactly - Same parameters, same return type (or covariant).

2. Access cannot be more restrictive - Can-t override public as private.

3. Exceptions can-t be broader - Can-t override throwing checked exception with unchecked.

4. Base method must be virtual or abstract.

public class Person
{
public virtual void Print(string name)
=> Console.WriteLine(name);
}

public class Student : Person
{
public override void Print(string name) // ? Exact match
=> Console.WriteLine($"Student: {name}");

// Error - different signature
// public override void Print(string name, int id) { }

// Error - more restrictive access
// private override void Print(string name) { }
}

Follow Liskov Substitution Principle: subclass can be used anywhere base is used.

🤖Use AI to Learn Faster

Use ChatGPT, Claude, or Copilot to go deeper on C# method overloading vs overriding. Try these prompts:

  • "Explain method overloading vs overriding in C# - what is the key difference?"
  • "Can I override a non-virtual method in C#? What happens?"
  • "Is method overloading compile-time or runtime polymorphism in C#?"
  • "Quiz me: show code and ask whether it is overloading or overriding"

💡 Tip: After reading this article, paste your own code into AI and ask "What could go wrong here and why?" — fastest way to find edge cases and deepen understanding.

Next Article

C# Version History ->

nexcoding.in