Why does calling a method in my derived class call the base class method?

Consider this code:

class Program
{
    static void Main(string[] args)
    {
        Person person = new Teacher();
        person.ShowInfo();
        Console.ReadLine();
    }
}

public class Person
{
    public void ShowInfo()
    {
        Console.WriteLine("I am Person");
    }
}
public class Teacher : Person
{
    public new void ShowInfo()
    {
        Console.WriteLine("I am Teacher");
    }
}

When I run this code, the following is outputted:

I am Person

However, you can see that it is an instance of Teacher, not of Person. Why does the code do that?


There's a difference between new and virtual/override.

You can imagine, that a class, when instantiated, is nothing more than a table of pointers, pointing to the actual implementation of its methods. The following image should visualize this pretty well:

Illustration of method implementations

Now there are different ways, a method can be defined. Each behaves different when it is used with inheritance. The standard way always works like the image above illustrates. If you want to change this behavior, you can attach different keywords to your method.

1. Abstract classes

The first one is abstract. abstract methods simply point to nowhere:

Illustration of abstract classes

If your class contains abstract members, it also needs to be marked as abstract, otherwise the compiler will not compile your application. You cannot create instances of abstract classes, but you can inherit from them and create instances of your inherited classes and access them using the base class definition. In your example this would look like:

public abstract class Person
{
    public abstract void ShowInfo();
}

public class Teacher : Person
{
    public override void ShowInfo()
    {
        Console.WriteLine("I am a teacher!");
    }
}

public class Student : Person
{
    public override void ShowInfo()
    {
        Console.WriteLine("I am a student!");
    }
}

If called, the behavior of ShowInfo varies, based on the implementation:

Person person = new Teacher();
person.ShowInfo();    // Shows 'I am a teacher!'

person = new Student();
person.ShowInfo();    // Shows 'I am a student!'

Both, Students and Teachers are Persons, but they behave different when they are asked to prompt information about themselves. However, the way to ask them to prompt their information, is the same: Using the Person class interface.

So what happens behind the scenes, when you inherit from Person? When implementing ShowInfo, the pointer is not pointing to nowhere any longer, it now points to the actual implementation! When creating a Student instance, it points to Students ShowInfo:

Illustration of inherited methods

2. Virtual methods

The second way is to use virtual methods. The behavior is the same, except you are providing an optional default implementation in your base class. Classes with virtual members can be instanciated, however inherited classes can provide different implementations. Here's what your code should actually look like to work:

public class Person
{
    public virtual void ShowInfo()
    {
        Console.WriteLine("I am a person!");
    }
}

public class Teacher : Person
{
    public override void ShowInfo()
    {
        Console.WriteLine("I am a teacher!");
    }
}

The key difference is, that the base member Person.ShowInfo isn't pointing to nowhere any longer. This is also the reason, why you can create instances of Person (and thus it does not need to be marked as abstract any longer):

Illustration of a virtual member inside a base class

You should notice, that this doesn't look different from the first image for now. This is because the virtual method is pointing to an implementation "the standard way". Using virtual, you can tell Persons, that they can (not must) provide a different implementation for ShowInfo. If you provide a different implementation (using override), like I did for the Teacher above, the image would look the same as for abstract. Imagine, we did not provide a custom implementation for Students:

public class Student : Person
{
}

The code would be called like this:

Person person = new Teacher();
person.ShowInfo();    // Shows 'I am a teacher!'

person = new Student();
person.ShowInfo();    // Shows 'I am a person!'

And the image for Student would look like this:

Illustration of the default implementation of a method, using virtual-keyword

3. The magic `new` keyword aka "Shadowing"

new is more a hack around this. You can provide methods in generalized classes, that have the same names as methods in the base class/interface. Both point to their own, custom implementation:

Illustration of the "way around" using the new-keyword

The implementation looks like the one, you provided. The behavior differs, based on the way you access the method:

Teacher teacher = new Teacher();
Person person = (Person)teacher;

teacher.ShowInfo();    // Prints 'I am a teacher!'
person.ShowInfo();     // Prints 'I am a person!'

This behavior can be wanted, but in your case it is misleading.

I hope this makes things clearer to understand for you!


Subtype polymorphism in C# uses explicit virtuality, similar to C++ but unlike Java. This means that you explicitly have to mark methods as overridable (i.e. virtual). In C# you also have to explicitly mark overriding methods as overriding (i.e. override) to prevent typos.

public class Person
{
    public virtual void ShowInfo()
    {
        Console.WriteLine("I am Person");
    }
}

public class Teacher : Person
{
    public override void ShowInfo()
    {
        Console.WriteLine("I am Teacher");
    }
}

In the code in your question, you use new, which does shadowing instead of overriding. Shadowing merely affects the compile-time semantics rather than the runtime semantics, hence the unintended output.


You have to make the method virtual and you have to override the function in the child class, in order to call the method of class object you put in parent class reference.

public class Person
{
    public virtual void ShowInfo()
    {
        Console.WriteLine("I am Person");
    }
}
public class Teacher : Person
{
    public override void ShowInfo()
    {
        Console.WriteLine("I am Teacher");
    }
}

Virtual Methods

When a virtual method is invoked, the run-time type of the object is checked for an overriding member. The overriding member in the most derived class is called, which might be the original member, if no derived class has overridden the member. By default, methods are non-virtual. You cannot override a non-virtual method. You cannot use the virtual modifier with the static, abstract, private or override modifiers, MSDN.

Using New for Shadowing

You are using new key word instead of override, this is what new does

  • If the method in the derived class is not preceded by new or override keywords, the compiler will issue a warning and the method will behave as if the new keyword were present.

  • If the method in the derived class is preceded with the new keyword, the method is defined as being independent of the method in the base class, This MSDN article explains it very well.

Early binding VS Late binding

We have early binding at compile time for normal method (not virtual) which is the currrent case the compiler will bind call to method of base class that is method of reference type (base class) instead of the object is held in the referece of base class i.e. derived class object. This is because ShowInfo is not a virtual method. The late binding is performed at runtime for (virtual / overridden method) using virtual method table (vtable).

For a normal function, the compiler can work out the numeric location of it in memory. Then it when the function is called it can generate an instruction to call the function at this address.

For an object that has any virtual methods, the compiler will generate a v-table. This is essentially an array that contains the addresses of the virtual methods. Every object that has a virtual method will contain a hidden member generated by the compiler that is the address of the v-table. When a virtual function is called, the compiler will work out what the position is of the appropriate method in the v-table. It will then generate code to look in the objects v-table and call the virtual method at this position, Reference.