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 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 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 {
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 {
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.