arcane_vander
arcane_vander

Reputation: 93

Simple C# OOP inheritance query

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

Answers (5)

Theodoros Chatzigiannakis
Theodoros Chatzigiannakis

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

Mitch
Mitch

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

David
David

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

planetarian
planetarian

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

Guffa
Guffa

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

Related Questions