What is the difference between virtual, override and new (method hiding)?

C# OOP Intermediate 2–3 Yrs3–5 Yrs Conceptual 2 min read

Quick Answer

virtual marks a base method as overridable. override in a derived class replaces it — calls are dispatched to the derived version even through a base-type reference (true polymorphism). new hides the base method instead: which method runs depends on the compile-time type of the reference, not the actual object.

virtual says “this method can be overridden”. override in a subclass actually replaces it, and the important part is that the call is resolved at runtime based on the real object — so a base-class reference pointing at a derived object still calls the derived method. new is method hiding: it looks similar, but the method that runs is chosen by the compile-time type of the variable, not the object. So if I have an Animal variable holding a Dog, override gives me Dog's behaviour and new gives me Animal's. new is almost always a mistake — I'd use virtual/override.

Given Animal a = new Dog();:

  • If Speak() is virtual in Animal and override in Dog, then a.Speak() runs Dog.Speak() — the runtime looks at the real object.
  • If Dog declares new void Speak(), then a.Speak() runs Animal.Speak() (reference is typed Animal), but ((Dog)a).Speak() runs Dog.Speak().

new just silences the compiler warning about hiding; it does not participate in polymorphism and is usually a design smell. Prefer virtual/override. Related keywords: abstract (virtual with no body, must override), sealed override (override but block further overriding), base.Method() (call the base implementation from the override).

C# — override vs new
class Animal { public virtual string Speak() => "..."; }

class Dog : Animal { public override string Speak() => "Woof"; }
class Cat : Animal { public new string Speak() => "Meow"; }   // hides

Animal d = new Dog();
Animal c = new Cat();
d.Speak();          // "Woof"  — polymorphic
c.Speak();          // "..."   — base version! (reference is Animal)
((Cat)c).Speak();   // "Meow"