CodeGym /Courses /C# SELF /Virtual Methods in C#: Polymorphism and Overriding

Virtual Methods in C#: Polymorphism and Overriding

C# SELF
Level 20 , Lesson 2
Available

1. Introduction

Imagine you have a base class Animal with a method Speak(). By default, for all animals it prints "Some sound". You want to create child classes, like Dog and Cat, so they say their real phrases ("Woof!" and "Meow!") instead of "Some sound".

You could write your own Speak() method in each child, but if you're working with a collection like Animal[], calling animal.Speak() will still call the Animal method, not the dog or cat one — because by default, C# looks at the type of the variable, not the actual object behind it.

Here's a simple example:


Animal dog = new Dog();
dog.Speak(); // Whoa, what will it print?

By default — "Some sound", not "Woof!", even if Dog has its own Speak() method. So what do you do? You need to declare the method as virtual (in the base class) and override (in the child).

What is a virtual method?

virtual method — that's a method declared in the base class with the virtual modifier, and it's meant to be overridden ( override) in child classes.

When you call such a method through a reference to the base class, the method of the "real" object gets called — just like in real life: if you tame an animal and it's a cat, it'll say "Meow!", not "Some sound".

Virtual methods are the foundation of polymorphism in C#.

2. Declaring Virtual Methods

How to declare a virtual method

In the base class, declare the method with the virtual keyword:


public class Animal
{
    public virtual void Speak()
    {
        Console.WriteLine("Some sound");
    }
}
Declaring a virtual method in the base class

In the child class, use the override keyword:


public class Dog : Animal
{
    public override void Speak()
    {
        Console.WriteLine("Woof!");
    }
}

public class Cat : Animal
{
    public override void Speak()
    {
        Console.WriteLine("Meow!");
    }
}
Overriding a virtual method in child classes

Example: showing off polymorphism


// For example, in Program.cs

// Base class Animal with a virtual Speak method
public class Animal
{
    public virtual void Speak()
    {
        Console.WriteLine("Some sound");
    }
}

// Dog class, overrides Speak behavior
public class Dog : Animal
{
    public override void Speak()
    {
        Console.WriteLine("Woof!");
    }
}

// Cat class, also overrides Speak
public class Cat : Animal
{
    public override void Speak()
    {
        Console.WriteLine("Meow!");
    }
}

public static class Program
{
    public static void Main()
    {
        Animal[] animals = new Animal[]
        {
            new Animal(),
            new Dog(),
            new Cat()
        };

        foreach (Animal animal in animals)
        {
            animal.Speak(); // Will print: "Some sound", "Woof!", "Meow!"
        }
    }
}

See the magic of virtual methods? Even if the variable is of type Animal, the method version of the actual implementation gets called.

3. What's Happening "Under the Hood": The Virtual Table

Quick rundown of the mechanism

When you declare a method as virtual, the compiler adds it to a special "virtual table" of methods for each type (kind of like a cafeteria menu for each dish). When such a method is called, C# doesn't look at the variable type, but at what's actually referenced — and "serves up" the method that matches the real object type.

You could say C# swaps in the right recipe instead of the generic one, if the class has its own version.

Analogy: a contract with a "fine print" clause

Imagine you have a rental contract (base class), and it says the tenant pays a fixed amount every month by default (the PayRent() method). But you're a sneaky landlord — you allow special conditions in the contract appendix (virtual method). If one of the tenants (child class) uses this right, they write their own override, and now the payment is handled in a special way.

4. When Should You Use Virtual Methods?

  • If a method in the base class should work for most children, but some of them might need their own behavior.
  • When you're building a class hierarchy where you expect to extend or change some logic.
  • When you're designing a flexible architecture, like for business logic, where different types of operations might need custom behavior.

In real projects, virtual methods are the backbone of the Template Method pattern, Strategy pattern, and honestly, like half of OOP.

Comparison with regular methods

Regular method Virtual method
Can be overridden No Yes (override)
How it's called By variable type By the "real" object type
Polymorphism No Yes

Frequently Asked Questions

  • Can you make a constructor virtual?
    Nope! Constructors are never virtual — they always work strictly by object type.
  • Can virtual methods be static?
    No, only instance methods can be virtual. Static methods don't participate in polymorphism, 'cause there's no object — so who's gonna override it?
  • Can fields be virtual?
    No, only methods, properties, and events.

5. Practice: Expanding the "Animal World" App

In our training app, you've already built a simple animal hierarchy. Let's add new virtual methods to animals, so different animals can eat in their own way!

Code example with comments


// In the base class, set up a virtual Eat method
public class Animal
{
    public virtual void Speak()
    {
        Console.WriteLine("Some sound");
    }

    public virtual void Eat()
    {
        Console.WriteLine("Eats generic food.");
    }
}

// In Dog, override Eat
public class Dog : Animal
{
    public override void Speak() => Console.WriteLine("Woof!");
    public override void Eat() => Console.WriteLine("Eats dog food.");
}

// In Cat, its own behavior too
public class Cat : Animal
{
    public override void Speak() => Console.WriteLine("Meow!");
    public override void Eat() => Console.WriteLine("Eats fish.");
}

public static class Program
{
    public static void Main()
    {
        Animal[] animals = new Animal[]
        {
            new Animal(),
            new Dog(),
            new Cat()
        };
        foreach (var animal in animals)
        {
            animal.Speak();
            animal.Eat();
            Console.WriteLine("---");
        }
    }
}

That's it, now every kitty and doggy eats their own way! And the base Animal keeps eating something weird, like a true default functionality.

6. Common Mistakes and Gotchas

  • You might forget override in the child — and then the base class method will stay in place.
  • Or, on the flip side, forget virtual in the base class, and then you can't write override in the child.

You can't write override without virtual

The C# compiler won't let you override a method that wasn't declared as virtual (or abstract) in the base class.

Why do you need override

override clearly tells the compiler and code reader: "I'm not just writing a new method — I'm intentionally changing what's set in the base class." This helps prevent mistakes when you want to "override" but accidentally just write a new method with a similar signature.

If you forgot override and wrote a new method

public class Dog : Animal
{
    public void Speak()
    {
        Console.WriteLine("Woof!");
    }
}
This is NOT overriding! Polymorphism doesn't work.

But this is not overriding! If you access Dog through a variable of type Animal, the animal's method ("Some sound") will be called, not the dog's. Oh, those surprise encounters with types!

2
Task
C# SELF, level 20, lesson 2
Locked
Creating a class with a virtual method
Creating a class with a virtual method
2
Task
C# SELF, level 20, lesson 2
Locked
Virtual method with additional logic
Virtual method with additional logic
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION