I do not understand why the following output is printed.
Static Type is Base and call to print() and leads to console output:
Static Type is Sub and call to print() and leads to console output:
Why is here Base.B called and not Sub.B?
Static Type is Sub and call to B() leads to console output:
The hidden Function B() on Sub is called in the program. But not if I call it with print().
static void Main(string[] args)
{
Base b = new Sub();
Sub s = b as Sub;
b.print(); //See first paragraph with 2 bullet points
s.print(); //See second paragraph bullet points
s.B(); //See third paragraph with bullet points
}
public class Base
{
public Base() {}
public void print()
{
A();
B();
}
public virtual void A() { Console.WriteLine("Base.A"); }
public void B() { Console.WriteLine("Base.B"); }
}
public class Sub : Base
{
public Sub() { }
public override void A() { Console.WriteLine("Sub1.A"); }
public new void B() { Console.WriteLine("Sub1.B"); }
}
The difference lies in how each method is called from each place, and it comes down to differences between new
and virtual
/override
.
First the theory, an oversimplified explanation of both keywords:
new
just defines another method in a derived class with the very same name of an existing method in a base class "hiding" it. The choice of what method to call (base or derived) is took at compile time, based on the type of the reference used to call the method.virtual
indicates that a method could have an alternative implementation in a derived class and in such case it should be used instead. Here the choice is made at runtime based on the type of the actual object.Now applying it your case.
All calls to A
are exactly the same here, since it's virtual and the only instance lying around is of type Sub
. Dynamic dispatch does its thing and this result in a call to Sub.B
as you've found.
But the calls on B
are on two places. The one inside the print
method and other on main
directly. As B
isn't virtual
it uses static dispatch and the compile time type of its reference to determine the call site. The one from main
is easy enough to see why it uses Sub.B
. The other within the print
method however doesn't uses the same references, they call an instance method within the same class using the this
pointer implictly. It's totally equivalent to writing this:
public void print()
{
this.A();
this.B();
}
So the call to B
depends entirely on the compile time type of this
, that is Base
in this case (as it's written in that class). So Base.B
is invoked here.
The fact that the previous call to print
came from another type of variable is irrelevant here, as that's only used to determine what print
implementation to take (here we have only one), but whatever actions are done by the method itself are beyond that and therefore don't influence its behavior.