5

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.

2
  • 2
    I do not understand the need for downvoting this question. At the least leave a comment so that I may improve it. Commented Aug 12, 2013 at 14:56
  • 1
    Your question is fine, and frankly a good one. Ignore the haters, they are out of control on the site these days IMO. Commented Aug 12, 2013 at 15:00

2 Answers 2

3

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.

Sign up to request clarification or add additional context in comments.

2 Comments

You maybe need to take a look at the new keyword in method signature. This will call the method on the actual type not as override.
@Sebi: There is no keyword new used to hide any methods in the OP's code.
0

It says "callvirt" - the virtual table is associated with "Animal" class so that's where the call should be placed. After resolving the virtual table, during runtime, the intended method will be called.

Comments