Reputation: 93
Given the following classes:
interface IShape
{
void Draw();
}
class Rectangle : IShape
{
public void Draw() { }
}
class Square : Rectangle
{
public new void Draw() { }
}
Could someone explain what happens in the second Draw method?
Rectangle rect = new Rectangle();
rect.Draw();
rect = new Square();
rect.Draw();
Off hand, I would say the Draw method of the Square class will be called, but when I entered this into VS2013, the Draw method of the Rectangle class was called.
Upvotes: 3
Views: 139
Reputation: 29233
In the Square
class, the new
keyword tells the compiler that this is a completely new method that just happens to have the same signature as an inherited method. Because it is a coincidence, it should not override the inherited method.
In this case, when calling Draw()
through a Square
variable, the compiler will choose the new method. If it didn't choose the new method in this case, you'd have no way to call it at all, if you think about it. If you want to call the old Draw()
, you can still call it through a Rectangle
variable (even on the same instance).
This is called hiding and you can do it on any method. You won't need it often - and if possible, you should avoid it, because while its semantics are well-defined, it makes your source code a little bit confusing.
On the contrary, if you want to denote that this is not a coincidence and that your intentionally overrides the inherited method with the same signature, you should use the keyword override
on your new method. In this case, when calling Draw()
on an object, you will always get the Draw()
version of the class you used to create that object (new Square()
, new Rectangle()
, etc) no matter what variable you call it from.
Keep in mind that the method being overridden has to allow itself to be overridden first. For that to happen, it has to be marked as virtual
first - methods that aren't marked as virtual
can't be overridden.
This is called overriding, as the keyword says. You will see and use this one often, because it enables polymorphism, which is one of the core concepts of object-oriented programming.
Upvotes: 4
Reputation: 22311
When you use new
instead of override
, the method is not overridden, but hidden.
class Animal
{
public virtual void MakeSound() { Console.WriteLine("Animal called"); }
}
class Dog : Animal
{
// Note: You can not use override and new in the same class, on
// the same method, with the same parameters. This is just to
// show when "new" takes effect, and when "override" takes effect.
public override void MakeSound()
{
Console.WriteLine("Animal's MakeSound called for dog");
}
public new void MakeSound()
{
Console.WriteLine("Dog's MakeSound called");
}
}
public static class Program
{
public static void Main(string[] args)
{
Dog dogAsDog = new Dog();
Animal dogAsAnimal = dogAsDog;
// prints "Dog's MakeSound called"
dogAsDog.MakeSound();
// prints "Animal's MakeSound called for dog"
dogAsAnimal.MakeSound();
}
}
Upvotes: 1
Reputation: 10708
It will call the Rectangle
version of Draw
.
The reason for this is because the variable rect
is of type Rectangle
at compile time. Because you've overridden Square
's Draw
method via new
, the runtime cannot lookup the Square
version of Draw
at runtime - this would be a lookup in the Virtual Table or V-Table, which doesn't exist in this case because Draw
is not virtual
.
Note that the following will call the Square
version of Draw
Square sq = new Square();
sq.Draw();
Because sq
is known to be a Square
at compile time.
If you were to make Draw
a virtual
within Rectangle
, and change new
to override
, the original code would call Square.Draw
. This is allowed, even though Draw
is the implementation of an interface method.
It is also possible to make a new Interface Method. Consider the following:
internal interface IShape
{
void Draw();
}
internal class Rectangle : IShape
{
public void Draw() { }
}
internal class Square : Rectangle, IShape
{
public new void Draw() { }
}
In which case the code
IShape rect = new Rectangle();
rect.Draw();
rect = new Square();
rect.Draw();
will call the second form.
Upvotes: 1
Reputation: 19
Since you have boxed it as a Rectangle, and your Square class hides rather than overrides Rectangle's Draw(), the second call will execute Rectangle's Draw method.
Upvotes: 0
Reputation: 700790
If the Draw
method was virtual, then the actual type of the object would be used to determine which method to call, i.e. the Square.Draw
method.
As the method is not virtual, it's the type of the reference that determines which method to call, i.e. the Rectangle.Draw
method.
Upvotes: 2