C# Virtual, Override, and New Keywords Explained

In C#, method inheritance and polymorphism rely heavily on three fundamental keywords: virtual, override, and new. Understanding how these keywords interact is essential for managing method execution when working with base classes and derived types. This article breaks down the purpose of each keyword, explains the crucial distinction between runtime polymorphism and method hiding, and provides clear code examples to show how they behave in practice.

The virtual Keyword

The virtual keyword is applied to a method, property, or event in a base class to declare that its implementation can be altered by a derived class.

  • Default Implementation: Unlike abstract methods, a virtual method must provide a default implementation in the base class.
  • Opt-in Polymorphism: It acts as an open invitation to subclasses to customize the behavior using late binding.
  • Rule: A virtual method cannot be marked as static, abstract, or private.

The override Keyword

The override keyword is used in a derived class to replace an inherited member that was declared as virtual or abstract.

  • Runtime Polymorphism: When a method is overridden, the runtime determines which version of the method to execute based on the actual type of the object in memory, not the type of the reference variable pointing to it.
  • Preserving Signatures: The signature, return type, and access modifiers of the override method must match the original base member.

The new Keyword

When used as a method modifier, the new keyword explicitly hides an inherited member from a base class. This concept is often referred to as method shadowing or method hiding.

  • No Polymorphism: The new keyword breaks the polymorphic chain. It does not replace the base method; instead, it introduces an entirely separate method that happens to share the same name and signature.
  • Compile-Time Binding: The method called is determined by the compile-time type of the reference, not the actual object type at runtime.
  • Suppression of Warnings: If you define a method in a derived class with the same name as a base method without using override or new, the C# compiler generates a warning. Adding the new keyword suppresses this warning, confirming the hiding is intentional.

Summary of Differences

Feature virtual override new
Location Base class Derived class Derived class
Purpose Enables overriding Extends/replaces base logic Hides base logic
Binding Type Dynamic (Late) Dynamic (Late) Static (Early)
Polymorphic Yes Yes No

Code Example

The distinction between override and new becomes immediately apparent when an instance of a derived class is held in a base class reference variable:

using System;

public class BaseClass
{
    public virtual void ShowMessage()
    {
        Console.WriteLine("BaseClass implementation");
    }
}

public class OverrideClass : BaseClass
{
    public override void ShowMessage()
    {
        Console.WriteLine("OverrideClass implementation");
    }
}

public class NewClass : BaseClass
{
    public new void ShowMessage()
    {
        Console.WriteLine("NewClass implementation");
    }
}

class Program
{
    static void Main()
    {
        // 1. Calling via BaseClass reference
        BaseClass obj1 = new OverrideClass();
        BaseClass obj2 = new NewClass();

        obj1.ShowMessage(); // Output: OverrideClass implementation
        obj2.ShowMessage(); // Output: BaseClass implementation

        // 2. Calling via Derived type reference
        NewClass obj3 = new NewClass();
        obj3.ShowMessage(); // Output: NewClass implementation
    }
}

In this example, calling ShowMessage() on obj1 invokes the method from OverrideClass because the method was overridden using dynamic dispatch. In contrast, calling ShowMessage() on obj2 invokes the method from BaseClass because NewClass merely hid the method, causing the call to resolve to the base implementation based on the variable's declared type.