When you instantiate Shape square = new Square();
, the fact that square
really is a Square
really is intact. Remember that the variable square
really is a reference to the real object. The reference type (in this case, Shape
) must be the same class or higher up the inheritance hierachy than the instantiated type (Square
), as you have here.
After instantiation, when the compiler sees square
, it first knows that it's the abstract type Shape
because that's the type of the reference. So, it must be a sub-type of Shape since you can't instantiate an abstract object. Since you said new Square();
the compiler will know the exact type. Again, the exact type of an object is not lost just because you assigned it to a baser (more base) type.
When you call square.PrintName();
, the compiler first sees that square
is declared with the abstract type Shape
, who has a method PrintName()
, also marked abstract. This tells the compiler to go look for the same exact method in the child class. If it finds PrintName()
in the child class, all is well - the correct function will be executed. If not, you get an error because the word abstract in the base class definition requires you to implement it.