Confusion about virtual/new/override
c#, keyword, new-operator, overriding, virtual
Solution
Here's how you think of virtual methods. Every instance of a class has "boxes" to hold methods. When you mark a method as `virtual` it says make a new "box" and put a method in it. When you mark a method as `override` in a derived class, it keeps the "box" from the base class but puts a new method in it.
So here you have a class `A` and a method named `mVVirtual` that is marked as `virtual`. This says make a new "box" named `mVVirtual` and put a method in it with definition
Console.WriteLine("A::mVVirtual");
Then you have a derived class `B` and a method named `mVVirtual` that is marked as `virtual`. This says make a new "box" named `mVVirtual` and put a method in it with definition
Console.WriteLine("B::mVVirtual");
In particular, the "box" inherited from `A` is hidden! It can not be seen by objects that are typed as `B`s or classes that derive from `B`.
Then you have a derived class `C` and a method named `mVVirtual` that is marked as `override`. This says take the "box" named `mVVirtual` inherited from `B` and put a different method in it with definition
Console.WriteLine("C::mVVirtual");
Now, when you have
B b1 = new C();
b1.mVVirtual();
you are telling the compiler that `b1` is a `B` so that `b1.mVVirtual()` looks in the "box" `mVVirtual` and finds the method with definition
Console.WriteLine("C::mVVirtual");
because `b1` is really a `C` and that is what is in the "box" `mVVirtual` for instances of `C`.
But when you have
A a2 = new C();
a2.mVVirtual();
you are telling the compiler that `a2` is an `A` and so it looks in the "box" and finds
Console.WriteLine("A::mVVirtual");
The compiler can not know that `a2` is really a `C` (you've typed it as an `A`) so it does not know that `a2` is really an instance of a class that is derived from a class that has hidden the "box" `mVVirtual` defined by `A`. What it does know is that `A` has a "box" named `mVVirtual` and so it emits code to invoke the method in that "box".
So, to try to put this succinctly:
class A {
public virtual void mVVirtual() { Console.WriteLine("A::mVVirtual"); }
}
defines a class that has a "box" with full name `A::mVVirtual` but that you can refer to by the name `mVVirtual`.
class B : A
{
// "new" method; compiler will tell you that this should be marked "new" for clarity.
public virtual void mVVirtual() { Console.WriteLine("B::mVVirtual"); }
}
defines a class that has a "box" with full name `B::mVVirtual` but that you can refer to by the name `mVVirtual`. Referring to `B.mVVirtual` will not refer to the "box" with full name `A::mVVirtual`; that "box" can not be seen by objects that are typed as `B`s (or classes that derive from `B`).
class C : B
{
public override void mVVirtual() { Console.WriteLine("C::mVVirtual"); }
}
defines a class that takes the "box" with full name `B::mVVirtual` and puts a different method in it.
Then
A a2 = new C();
a2.mVVirtual();
says that `a2` is an `A` so that `a2.mVVirtual` looks in the "box" with full name `A::mVVirtual` and invokes the method in that "box". This is why you see
A::mVVirtual
on the console.
There are two other method annotaters. `abstract` makes a new "box" does not put a method definition in the "box". `new` makes a new "box" and puts a method definition in the "box" but does not allow derived classes to put their own definitions of the method in the "box" (use `virtual` if you want to do that).
Sorry for being long-winded but I hope that helps.
Problem
I am a bit confused about the `virtual`/`new`/`override` thing. Here's an example: ``` class A { public virtual void mVVirtual() { Console.WriteLine("A::mVVirtual"); } } class B : A { public virtual void mVVirtual() { Console.WriteLine("B::mVVirtual"); } } class C : B { public override void mVVirtual() { Console.WriteLine("C::mVVirtual"); } } class Test { static void Main() { B b1 = new C(); b1.mVVirtual(); //C::mVVirtual ... I understand this A a2 = new C(); a2.mVVirtual(); //A::mVVirtual ... ??? } } ``` I don't get why in the second call we get `A::mVVirtual`. I usually treat these issues with this "algorithm": - Check the type of the variable holding the reference for the object for an instance method called `mVVirtual`? Doesn't have one...but does have a virtual method with that signature and name! - Virtual method? Let's then check the type of the object being held by `a2` (`C`) for an overriding of that method. It has one -> Executes `C::mVVirtual`! Where is my "algorithm" wrong? I really am confused by this, and would greatly appreciate some help.