Reputation: 121
I want to understand polymorphism in c# so by trying out several constructs I came up with the following case:
class Shape
{
public virtual void Draw()
{
Console.WriteLine("Shape.Draw()");
}
}
class Circle : Shape
{
public override void Draw()
{
Console.WriteLine("Circle.Draw()");
}
}
I understand that in order to send the Draw() message to several related objects, so they can act according to its own implementation I must change the instance to which (in this case) shape is 'pointing' to:
Shape shape = new Circle();
shape.Draw(); //OK; This prints: Circle.Draw()
But why, when I do this:
Circle circle = new Circle();
circle.Draw(); //OK; This prints: Circle.Draw()
Shape shape = circle as Shape; // or Shape shape = (Shape)circle;
shape.Draw();
It prints: "Circle.Draw()"
Why it calls the Circle.Draw() instead Shape.Draw() after the cast? What is the reasoning for this?
Upvotes: 12
Views: 2982
Reputation: 782
Let me explain it in terms of is-a, because the shape is
a circle:
Shape shape = circle as Shape;
The code explains itself perfectly, you are referring the circle as
a shape, the shape does not change at all, and it is
still a circle, although it is
also a shape.
You can even check if it is
a circle:
if (shape is Circle)
Console.WriteLine("The shape is a Circle!");
It is
a circle, right? So invoking Circle.Draw()
should be perfectly logical.
Upvotes: 0
Reputation: 525
As others have mentioned, casting an object doesn't change the actual instance; instead, casting allows a variable to assume a subset of characteristics of the instance from higher in the object hierarchy.
To demonstrate why it needs to work this way, consider this example:
//Some buffer that holds all the shapes that we will draw onscreen
List<Shape> shapesOnScreen = new List<Shape>();
shapesOnScreen.Add(new Square());
shapesOnScreen.Add(new Circle());
//Draw all shapes
foreach(Shape shape in shapesOnScreen)
{
shape.Draw();
}
Calling Draw() in the foreach loop will call the Draw() method of the derived instance, i.e. Square.Draw() and Circle.Draw(). This allows you, in this example, to draw each individual shape without knowing exactly which shape you're drawing at runtime. You just know you need a shape, let the shape handle how it's drawn.
If this was not the case (and this goes for inheritance in other languages, not just C#), you wouldn't be able to use anything but Shape.Draw().
Upvotes: 8
Reputation: 61379
The other answers are absolutely correct, but to try and go one level deeper:
Polymorphism is implemented by using something called a virtual function pointer table (vTable). In essence, you get something like:
Shape -> Shape.Draw()
Circle -> Circle.Draw()
When you call a function marked "virtual" the compiler does a typeof, and calls the most derived implementation of that function that is part of the types inheritance tree. Since Circle inherits from Shape, and you have a Circle object (as noted before, casting does not affect the underlying type), Circle.Draw is called.
Obviously this is an oversimplification of what actually happens, but hopefully it helps explain why polymorphic behavior acts the way it does.
Upvotes: 3
Reputation: 100630
Casting does not change run-time type of object and what implementation of particular virtual method each instance have.
Note that following 2 cases you have as sample are identical:
Shape shape = new Circle();
shape.Draw(); //OK; This prints: Circle.Draw()
and:
Circle circle = new Circle();
Shape shape = circle as Shape;
shape.Draw();
The first one is essentially shorter version of the second.
Upvotes: 13
Reputation: 48154
You're overriding the method in the inheriting class so it will always be the version that gets invoked regardless of whether your reference is to the less specific base class.
If you want to invoke the version in Shape
you need an instance of type Shape
not just a reference of that type.
Upvotes: 6