4

I'm confused with the following scenario, we have a set of classes like this

public class A
{
    public virtual string SomeMethod()
    {
        return "A";
    }
}

public class B : A
{
    public override string SomeMethod()
    {
        return "B";
    }
}

public class C : B
{
    public new virtual string SomeMethod()
    {
        return "C";
    }
}

public class D : C
{
    public override string SomeMethod()
    {
        return "D";
    }
}

When i call the following method

private void Test()
{
    A a = new D();
    B b = new D();
    C c = new D();
    D d = new D();
    Console.WriteLine(a.SomeMethod()); //The method in class B is being called
    Console.WriteLine(b.SomeMethod()); //The method in class B is being called
    Console.WriteLine(c.SomeMethod()); //The method in class D is being called
    Console.WriteLine(d.SomeMethod()); //The method in class D is being called
}

I'm getting the output like this

B B D D

Why is it that the inherited method is being called, instead of the method in the declared type, and why isn't the method in class D being called every time?

Vamsi
  • 4,237
  • 7
  • 49
  • 74

3 Answers3

4

When you call SomeMethod on an instance of A (i.e. A foo = new <A or derived>()), you expect to get the most derived version of SomeMethod available. That's the whole point of inheritance. Your code only needs to deal with instances of the base class, but if those instances happen to really be of a derived class, the special dervied implementations are invoked. This is the behavior you get when you override a method.

This explains common scenarios like

A b = new B();
b.SomeMethod();  // B's implementation invoked

With new, you are not overriding the method, you are declaring a brand new method with the same name. This method exists only on the class that declared it and its children, it's not part of the base classes and their inheritance chain.

So what does A a = new D(); a.SomeMethod(); do? The variable is declared as A, so any methods/properties/etc invoked against it have to be defined on A. C defined a new method SomeMethod (and D overrides it), but this method doesn't exist on A, so it cannot be invoked here. The most derived implementation of SomeMethod (as declared on type A) is in B, so this is the implementation which is invoked.

Same story for B b = new D(); b.SomeMethod();

It's only when we get to C c = new D(); c.SomeMethod() that the new method has a chance to execute. This is because the variable is a C, and thus the new method SomeMethod is for the first time declared on the variable type. And as stated above, the most derived possible version will be invoked, which in this case means the version overriden by D.

And I hope we are all on the same page for D d = new D(); d.SomeMethod() :)

Others have posted good links. Here's another thread that might help: C# and method hiding

And the last example here shows an even weirder scenario where the "new" method is declared as private, thus a further dervied type actually inherits the base version of the method, rather than inheriting the "new" version. http://msdn.microsoft.com/en-us/library/aa691135

Community
  • 1
  • 1
latkin
  • 16,402
  • 1
  • 47
  • 62
  • "The variable is declared as A, so any methods/properties/etc invoked against it have to be defined on A" if this is the case then why does `A obj = new A(); obj.SomeMethod();` call the method in `A` and not call the method in `B` ? – Vamsi Aug 31 '12 at 04:38
  • Because `obj` is declared and instantiated a `A`. You only have to worry about this stuff when you have a variable (or a method argument) that is declared as base class, but which is instantiated as a derived class. – latkin Aug 31 '12 at 16:12
3

I try to explain it in a different way.

virtual / override means, that you implement / change the behaviour of the same method. It is an implementation of polymorphism. With new, you create a completely new method. It happens to have the same signature as another method, but doesn't have anything to do with it.

When calling this methods, it depends on which type the reference has (compile time type), to choose the method you actually call.

Your code is equivalent to:

public class A
{
    public virtual string SomeMethod()
    {
        return "A";
    }
}

public class B : A
{
    public override string SomeMethod()
    {
        return "B";
    }
}

public class C : B
{
    public virtual string AnotherMethod()
    {
        return "C";
    }
}

public class D : C
{
    public override string AnotherMethod()
    {
        return "D";
    }
}

private void Test()
{
    A a = new D();
    B b = new D();
    C c = new D();
    D d = new D();
    Console.WriteLine(a.SomeMethod()); //The method in class B is being called
    Console.WriteLine(b.SomeMethod()); //The method in class B is being called
    Console.WriteLine(c.AnotherMethod()); //The method in class D is being called
    Console.WriteLine(d.AnotherMethod()); //The method in class D is being called
}

The compiler chooses to call AnotherMethod for reference of type C (and D).

Stefan Steinegger
  • 63,782
  • 15
  • 129
  • 193
  • "Why is it that the inherited method is being called, instead of the method in the declared type ?" – Vamsi Aug 30 '12 at 05:31
  • That's the whole sense of inheritance and overriding. It is called polymorphism: you call a method, the (runtime-) type itself knows what to do. http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming – Stefan Steinegger Aug 30 '12 at 05:48
  • My question is this if i create a instance like this `A obj = new A();` and call the method `obj.SomeMethod();` the output will be `A` but if i initialize the instance like this `A objTest = new D();` and then call the method `objTest.SomeMethod();` it will output `B`, why is this happening ? – Vamsi Aug 30 '12 at 05:55
  • 2
    Because at runtime, it is an the implementation of `D`. So it executes the `SomeMethod` implementation found in `D`, which is inherited from `B`. The `new SomeMethod` in your code that is implemented in `C` and `D` isn't called because this is a completely different method which just has the same name. That's what I try to show in my code. – Stefan Steinegger Aug 30 '12 at 06:15
2

That is a well-known behavior: when you hide method (with new) it is called only when you are accessing it through instance of hiding type; when you use instance of base class, original method is used.

Hiding is not overriding.

Sergei Rogovtcev
  • 5,804
  • 2
  • 22
  • 35