C# virtual methods

Mestering the art of object oriented programming...

Ah! and yet again we find ourselves in the deep rabbit hole of Object Oriented Programming. In this particular instance I will discuss a bit on the mysteries of polymorphism and in particular virtual method. Interestingly enough, in order to explain Virtual Methods I have to explain to you what a NON VIRTUAL method is … cope with me for a while, I will explain rather quickly.

In C#, all methods ARE NOT VIRTUAL by default. What does this mean? Well, let’s work with an example (you should be a little bit familiar with Inheritance as well, but don’t be afraid, this topic is a piece of cake, and in this case the cake is not a lie):

I will start with the following code:

using System;
using System.Collections.Generic;

namespace VirtualMethods
{
    class Animal
    {
        public Animal()
        {
            Console.WriteLine("Animal");
        }

        public void Eat()
        {
            Console.WriteLine("I eat like an Animal");
        }
    }

    class Dog : Animal
    {
        public Dog()
        {
            Console.WriteLine("Dog");
        }
 
        public void Eat()
        {
            Console.WriteLine("I eat like a Dog");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            List<Animal> animals = new List<Animal>() { new Animal(), new Dog() };

            foreach (Animal animal in animals)
            {
                animal.Eat();
            }

            // just to stop the console
            Console.ReadLine();
        }
    }
}

What do you think the output of the previous program will be? As you can see, in line 36 I am defining a list of Animal objects. C# allows me to add two objects to this list during declaration time (nice!). Then, thanks to the power of the foreach keyword I am easily navigating through each Animal object contained in the list and I am asking each of them to Eat().

Have you noticed that the List of Animal objects is filled with an Animal and a Dog? Well, this is valid since Dog extends from the Animal class, this is what Inheritance and Polymorphism is all about after all, isn’t it?

Now, to the juice of it. The output of the program is as follows:

Animal
Animal
Dog
I eat like an Animal
I eat like an Animal

Line 1 is the initialization of the first Animal Object. Lines 2 and 3 are the initialization of the Dog Object. Finally, both objects print “I eat like an Animal” when we invoke the Eat() method.

EXPLANATION!!! PAY ATTENTION!!! Dog is an object that defines a method Eat() with the same signature as its base class. When we call the Dog object through its base class, in this case through the Animal reference, the method that will be called will be that of the reference variable you are using, in this case the Animal reference.

Let’s continue.

What happens if I modify my Main method with the following code?

static void Main(string[] args)
{
    List<Animal> animals = new List<Animal>() { new Animal(), new Dog() };

    foreach (Animal animal in animals)
    {
        if (animal is Dog)
        {
            // cast to Dog
            ((Dog)animal).Eat();
        }
        else
        {
            animal.Eat();
        }
    }

    // just to stop the console
    Console.ReadLine();
}

For every iteration of the foreach keyword we are controlling the type of the current object. If this animal IS A Dog, we will cast this object to its proper type and execute the proper Eat method. Now the output will be the following:

Animal
Animal
Dog
I eat like an Animal
I eat like a Dog

So, in order to get the proper implementation for the Eat() method we need to cast the reference to the proper Type that defines the version of the method that we want to use. Confused? Read the previous statement slowly. You will find this is not rocket science.

The reason these classes behave like this IS BECAUSE THE Eat() METHOD WAS NOT DESIGNED TO BE OVERRIDABLE. What!? It means that a derived class of the Animal class will not be able to Override the Eat() method.

  • FACT 1: if you write the override keyword in the Eat() method of the Dog class, you will get a compilation error. Don’t believe me? try it out! This is because the method Eat() in the base class, in this case Animal, is not designed to be overridable.
  • FACT 2: What we were actually doing was just hiding the derived method of the Animal class. Visual Studio should have generated a warning with the following message if you pasted my code in there.

'VirtualMethods.Dog.Eat()' hides inherited member 'VirtualMethods.Animal.Eat()'. Use the new keyword if hiding was intended.

It is ok to hide inherited members (if that is your design). To avoid Visual Studio’s warning then do as it says and add the new keyword to the method’s declaration like this (The behavior will remain the same):

class Dog : Animal
{
    public Dog()
    {
        Console.WriteLine("Dog");
    }

    public new void Eat()
    {
        Console.WriteLine("I eat like a Dog");
    }
}

SO??? How can I tell C# that I want to have an Eat() method that can be overridable? ENTER “VIRTUAL” KEYWORD.

A Virtual Method is the method that is designed with the possibility to be overridden in the derived classes. So when we write our Animal, Dog and Program classes like this:

namespace VirtualFunctions
{
    class Animal
    {
        public Animal()
        {
            Console.WriteLine("Animal");
        }
 
        public virtual void Eat()
        {
            Console.WriteLine("I eat like an Animal");
        }
    }
 
    class Dog : Animal
    {
        public Dog()
        {
            Console.WriteLine("Dog");
        }
 
        public override void Eat()
        {
            Console.WriteLine("I eat like a Dog");
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            List<Animal> animals = new List<Animal>() { new Animal(), new Dog() };
 
            foreach (Animal animal in animals)
            {
                animal.Eat();
            }
 
            // just to stop the console
            Console.ReadLine();
        }
    }
}

What we will get as an output is:

Animal
Animal
Dog
I eat like an Animal
I eat like a Dog

DID YOU NOTICE THAT THERE WAS NO NEED OF A CAST FOR THE DOG OBJECT? This is like saying that a Dog behaves as a Dog even if you call it through the Animal reference. Finally, when you want to override a virtual method from a base class in a derived class YOU SHOULD USE THE override KEYWORD.

TIP FOR JAVA PROGRAMMER: In Java all member functions or methods of a class ARE VIRTUAL by default. If you want to avoid someone from overriding the behavior of a method in a derived class, you should use the keyword final in the declaration of your method.