Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Regarding Inheritance C#

Tags:

c#

inheritance

I am trying to understand how inheritance works in C#. I wrote the following code:

class Program
{
    static void Main(string[] args)
    {
        Animal animal = new Dog();
        animal.OverRideMe();
        //animal.NewMethod();
        Dog dog = (Dog)animal;
        dog.OverRideMe();
        dog.NewMethod();
        Console.Read();
    }
}
public abstract class Animal
{
    public Animal()
    {
        Console.WriteLine("Base Constructor");
    }
    public virtual void OverRideMe()
    {
        Console.WriteLine("In Base Class's OverRideMe");
        Console.Read();
    }
}
public class Dog : Animal
{
    public Dog()
    {
        Console.WriteLine("Derived Constructor");
    }
    public override void OverRideMe()
    {
        Console.WriteLine("In Derived Class's OverRideMe");
        Console.Read();
    }
    public void NewMethod()
    {
        Console.WriteLine("In Derived Class's NewMethod");
        Console.Read();
    }
}

The CIL(Common Intermediate Language) code for the Main() looks like the following:

.method private hidebysig static 
    void Main (
        string[] args
    ) cil managed 
{
    // Method begins at RVA 0x2050
    // Code size 42 (0x2a)
    .maxstack 1
    .entrypoint
    .locals init (
        [0] class ConsoleApplication1.Animal animal,
        [1] class ConsoleApplication1.Dog dog
    )

    IL_0000: nop
    IL_0001: newobj instance void ConsoleApplication1.Dog::.ctor()
    IL_0006: stloc.0
    IL_0007: ldloc.0
    IL_0008: callvirt instance void ConsoleApplication1.Animal::OverRideMe()
    IL_000d: nop
    IL_000e: ldloc.0
    IL_000f: castclass ConsoleApplication1.Dog
    IL_0014: stloc.1
    IL_0015: ldloc.1
    IL_0016: callvirt instance void ConsoleApplication1.Animal::OverRideMe()
    IL_001b: nop
    IL_001c: ldloc.1
    IL_001d: callvirt instance void ConsoleApplication1.Dog::NewMethod()
    IL_0022: nop
    IL_0023: call int32 [mscorlib]System.Console::Read()
    IL_0028: pop
    IL_0029: ret
} // end of method Program::Main

The lines in CIL that are troubling me are:

IL_000f: castclass ConsoleApplication1.Dog
IL_0014: stloc.1
IL_0015: ldloc.1
IL_0016: callvirt instance void ConsoleApplication1.Animal::OverRideMe()
IL_001b: nop
IL_001c: ldloc.1
IL_001d: callvirt instance void ConsoleApplication1.Dog::NewMethod()

After the castclass of animal to Dog type the code executes dog.OverRideMe();. This is translated to CIL as

IL_0016: callvirt instance void ConsoleApplication1.Animal::OverRideMe()

I had cast the animal object to Dog type. Why should dog.OverRideMe(); be translated to the above statement in CIL? The output of the above code is:

enter image description here

This output has nothing to do with Base class Animal but CIL still places a call to it.

like image 464
msiyer Avatar asked Oct 03 '22 06:10

msiyer


1 Answers

You're invoking a virtual method. Virtual method invocation is determined by the runtime type of an object. You can call it a Dog all you want, but the compiler is still going to emit instructions to determine the appropriate method to invoke at runtime. Starting with the compile-time type of dog, it walks up the inheritance chain until it finds the "top-level" definition1 of OverRideMe and it emits a virtual method invocation for that. In this case, the highest place in the inheritance chain that OverRideMe is defined is in Animal; thus, it emits a virtual method invocation for Animal.OverRideMe.

Here's a previous answer that might help you understand what is going on a little better.

1: The highest place in the inheritance chain where the method is defined. Some care has to be taken here to understand how method hiding and what not impact this.

like image 53
jason Avatar answered Oct 12 '22 10:10

jason