user1968030
user1968030

Reputation:

casting to base class, and calling its virtual method results in stackoverflow exception

Consider this code:

public class Person
{
    public virtual void UpdateLastLogin()
    {
        // business of last login here
    }
}

public class Student : Person
{
    public override void UpdateLastLogin()
    {
        // logging something specific to person
        ((Person)this).UpdatelastLogin();
    }
}

Why Above code throws STACKOVERFLOW exception?

But this doesn't:

public class Person
{
    public virtual void UpdateLastLogin()
    {
        // business of last login here
    }
}

public class Student : Person
{
    public override void UpdateLastLogin()
    {
        // logging something specific to person
        base.UpdatelastLogin();
    }
}

Upvotes: 11

Views: 2449

Answers (2)

Saeed Neamati
Saeed Neamati

Reputation: 35842

It's because base keyword disables virtual method invocation, but casting doesn't.

Let's break it down:

With virtuals and overrides, C# has an algorithm to find the correct method to call. This algorithm is called virtual method invocation.

When C# compiler is to invoke a method that has override modifier, it tries to find the most overriden method. That is, it goes down the inheritance hierarchy of the run-time type to find the most overriden method. In this case, when you cast the Student to its base class Person, in run-time, what you really have is a derived class from Person. Thus C# compiler tries to find the most overriden method, that is, a method that exists in the Student class, and it calls that method. But that method again tries to cast Student to Person and again the chain goes on and on. Thus you see StackOverflowException.

However, when you use base to call the overridden base method, then compiler treats with that method (Person.UpdateLastLogin) as a non-virtual method and won't apply virtual method invocation and resolution to it.

C# specification has a pretty reasonable explanation on override and virtual. I encourage you to read its 17.5.3 Virtual methods and 17.5.4 Override methods sections. Specifically quoted from specification:

A base-access disables the virtual invocation mechanism and simply treats the base method as a non-virtual method.

Upvotes: 17

Jonathon Reinhart
Jonathon Reinhart

Reputation: 137448

If you mean to call the base class implementation, use the base keyword:

base.UpdatelastLogin();

Casting the reference to the base class really does nothing. That's the beauty of object-oriented programming! You don't need to know what type something is - you simply call a method on an object, and it's up the the implementation of that object how to behave.

Once you instantiate the child class, the entry in that object's vtable for UpdateLastLogin() is always going to point to the child class, no matter the type of the reference.

Upvotes: 4

Related Questions