17

I read that the new modifer hides the base class method.

using System;

class A
{
    public void Y()
    {
        Console.WriteLine("A.Y");
    }
}

class B : A
{
    public new void Y()
    {
        // This method HIDES A.Y.
        // It is only called through the B type reference.
        Console.WriteLine("B.Y");
    }
}

class Program
{
    static void Main()
    {
        A ref1 = new A(); // Different new
        A ref2 = new B(); // Polymorpishm
        B ref3 = new B();

        ref1.Y();
        ref2.Y(); //Produces A.Y line #xx
        ref3.Y();
    }
}

Why does ref2.Y(); produce A.Y as output?

This is simple polymorphism, the base class object pointing towards derived class, so it should call the derived class function. I am actually Java cum C# coder; these concepts just boggled my mind.

When we say new hides the base class function, that means the base class function can't be called, that's what hides mean as far as I know.

ref

Sergey Kolodiy
  • 5,829
  • 1
  • 36
  • 58
  • 5
    Avoid using the `new` modifier. It introduces an unrelated member with the same name (and signature in case of methods like here), but the original (inherited) member is also there. That leads to confusion. In your example, a `B` instance has ***two*** instance methods called `Y()`. With `ref3.Y()` you see that the one declared in `B` is preferred over the one inherited. That is all "hiding" means. If you really want an unrelated method, use an unused name and avoid the need for `new`. If you wanted polymorphism, use `override` as suggested by the answer. – Jeppe Stig Nielsen Apr 02 '14 at 11:25
  • @JeppeStigNielsen ref3.Y() is purely class B call, I haven't mentioned Y() as virtual, so its not inherited at all, If I say the cat hides the child, that means the cat is in front of the child, similarly if the derived class function hides the base class function, then the derived class function should get called since base class one is hidden –  Apr 02 '14 at 11:53
  • 1
    Non-virtual methods are inherited for sure. – Jeppe Stig Nielsen Apr 02 '14 at 12:08
  • @JeppeStigNielsen I got that, may be too much java coding ruined my concepts. Thank you anyways –  Apr 02 '14 at 12:09
  • 2
    The only thing about this "hide" terminology, is this: If a type has two identically looking members, one of which was inherited from some base class, and the other one is declared in this class, the ambiguity is resolved by choosing the method from the more specialized class. That is all there is to it. The `new` modifier doesn't actually change anything (other than suppressing a compile-time warning). You get the exact same behavior without `new` (if you tolerate compiler warnings). The `new` is just for telling the compiler "I know I am doing something stupid, relax". – Jeppe Stig Nielsen Apr 02 '14 at 12:12
  • possible duplicate of [C# keyword usage virtual+override vs. new](http://stackoverflow.com/questions/159978/c-sharp-keyword-usage-virtualoverride-vs-new) – jww Apr 06 '14 at 09:20

3 Answers3

27

In C#, methods are not virtual by default (unlike Java). Therefore, ref2.Y() method call is not polymorphic.

To benefit from the polymorphism, you should mark A.Y() method as virtual, and B.Y() method as override.

What new modifier does is simply hiding a member that is inherited from a base class. That's what really happens in your Main() method:

A ref1 = new A();
A ref2 = new B();
B ref3 = new B();

ref1.Y(); // A.Y
ref2.Y(); // A.Y - hidden method called, no polymorphism
ref3.Y(); // B.Y - new method called
Sergey Kolodiy
  • 5,829
  • 1
  • 36
  • 58
  • 1
    Can you also add an explanation for what the `new` modifier actually does? Jeppe Stig Nielsen's comment contains such valuable information. – Jeroen Vannevel Apr 02 '14 at 11:28
  • @Sergey so if I do ref2.(dot) I will get all the members and variables defined in class B, right? still it is pointing to object of that class right? –  Apr 02 '14 at 11:50
  • 2
    @user1765876 The _compile-time type_ of `ref2` is `A`. However, the _run-time type_ of the object `ref2` refers is `B`. Doing `ref2.MemberThatDoesNotExistInA` is a compile-time error. Doing `ref2.MemberFromA` is OK. If the member is non-virtual (no `virtual`, `abstract` or `override` modifiers), you get the implementation from the `A` class. Only if the member is `virtual` can you get an overridden implementation (if `B` provides one). – Jeppe Stig Nielsen Apr 02 '14 at 12:04
  • @JeppeStigNielsen so basically I can't do this ref2.MemberfromB... where MemberfromB is non-inherited variable or method. –  Apr 02 '14 at 12:19
  • @user1765876 It is just like you cannot say `object obj = XXX; obj.TransferMoney(1000m);`. There is static typing here; `object` does not contain a method called `TransferMoney`. It could be that the compile-time type of `obj` actually contained such a method, but how would the compiler know that? It can't remember that this came from `XXX`, and it might not know what `XXX` returns. – Jeppe Stig Nielsen Apr 02 '14 at 12:57
5

(Just to supplement other answers, and comments by myself.)

When one uses new, the class (or struct, or interface) will have two same-looking members, one inherited from a base type, and one declared by the type itself. Avoid that!

Important: Just because you say new, you will not "remove" the old member. It is still there, and can easily be called. The new member does not replace the inherited one. It is an unrelated member which happens to have the same name.

It is not good to have two or more members in a type that look the same. It leads to confusion. Consider the code:

interface IOne
{
  void Y();
}
interface ITwo
{
  void Y();
}
interface IBoth : IOne, ITwo
{
}
class Test
{
  static void M(IBoth obj)
  {
    obj.Y();  // must not compile!
  }
}

The type IBoth has two members (both inherited) which look the same. Depending on what concrete class obj is, those methods might have different implementations. The call obj.Y() is ambiguous. You will have to cast obj to one of the base interfaces to resolve this.

Then consider this code:

interface IBase
{
  void Y();
}
interface IDerived : IBase
{
  /* new */ void Y();
}
class Test
{
  static void M(IDerived obj)
  {
    obj.Y();  // allowed; IDerived has two Y, but one hides the other
  }
}

This time, there are two Y(), but one is sort of "nearer" than the other one. So the nearer one is preferred. However the compiler will give you a warning if you don't use new. If you do use new, that changes nothing other than making the compile-time warning go away. It is really a bad idea to make two Y() on purpose.

This situation can happen if the base type (here IBase) is written by some other vendor/supplier. Example: Maybe you introduced Y() in your interface at a time when the base didn't have that functionality. But then the vendor of IBase is releasing a new version of their product where IBase has the Y(). Now if you compile your code against their new version, "your" Y() will still be called, not theirs. But it will give this warning. The warning goes away if you include new. But it is better to either (1) remove your Y() method completely if you determine that the vendor's Y() does the job, or (2) rename your Y() method to some unused name.

If what you wanted was polymorphism, of course use abstract/virtual (class members only) combined with override (in the inheriting class). override will not introduce any new members, just a new implementation of an existing (inherited) member. This can be done for non-static members (typically methods or properties) only.

Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181
1

The type of the object is A, but ref2 does not access the version of Y() that is defined in the B class because that method is declared with the new modifier, not the override modifier. As a result, a ref2 object displays the same description as an A object.

Syed Shoaib Abidi
  • 2,356
  • 17
  • 19
  • 1
    new modifier actually hides the method of base class but if the type of object is base then it would not hide , you'll have to use virtual and override in C#. Hope this helps. – Syed Shoaib Abidi Apr 02 '14 at 11:29
  • any reference to the point "f the type of object is base then it would not hide " –  Apr 02 '14 at 11:55
  • 1
    Here is the link which could be useful for you: http://msdn.microsoft.com/en-us/library/ms173153.aspx – Syed Shoaib Abidi Apr 02 '14 at 11:58