views:

181

answers:

6

I have just learned how to mask a base class member (using new) but am missing the point as to why I would want to do that. Does masking provide us with a certain level of protection as is the case in using encapsulation? Please advise.

+3  A: 

It's not just used for masking. It actually breaks the inheritance chain, so if you call the base class method, the method in the derived class will not be called (just the one in the base class).

You're essentially creating a new method that has nothing to do with the base class method. Hence the "new" keyword.

Keeping that in mind the "new" keyword can be used if you want to define a method with the same signature as a base type method, but having a different return type.

Philippe Leybaert
But that don't really explain why you'd want to do that. (i.e., all you done is tell how is function you wrote is NOT called -- if it not called, what's the point?)
James Curran
Why? If you don't want the new method to be part of the same inheritance chain of a virtual method with the same name and parameter types. As a side-effect, it allows you to redeclare a method with the same signature, except for the return type. As long as you remember that it won't be called when you call the base type's method.
Philippe Leybaert
Your "as a side-effect" sentence answers the question. The rest can be accomplished better by either a) giving the method a different name, or b) just not writing it at all.
James Curran
+3  A: 

You will very rarely use "new" to mask a base class member.

It's mainly used for the cases where the derived class had the member first, and then it was added to the base class --- the same name for a different purpose. The new is there to that you acknowledge that you know you are using it differently. When a base member is added in C++, it just silently merges the existing method into the inheritance chain. In C#, you will have to choose between new and override, to show you know what is happening.

James Curran
+1 this is _probably_ the most common usage, but I still dislike it because the lack of polymorphism breaks intent (and who knows what else) of the derived.
Marc
+3  A: 

The only valid safe examples that I've come across is being more specific with return types or providing a set accessor on a property. I'm not saying those are the only ones, but that's all I've found.

For example, suppose you have a very simple base that looks like this:

public abstract class Base
{
  public string Name { get; protected set; }

  public Base(string name)
  { Name = name; }
}

You could have a derived that looks more like this:

public class Derived : Base
{
  public new string Name 
  {
    get { return base.Name; }
    set { base.Name = value; }
  }

  public Derived(string name) : base(name)
  { }         
}

Assuming business rules allows this one specific Derived to have a changeable name, I believe this is acceptable. The problem with new is that it changes behavior depending on what type the instance is viewed as. For example, if I were to say:

Derived d = new Derived("Foo");
d.Name = "Bar";
Base b = d;
b.Name = "Baz"; // <-- No set available.

In this trivial example, we're fine. We are overriding the behavior with new, but not in a breaking way. Changing return types requires a bit more finesse. Namely, if you use new to change a return type on a derived type, you shouldn't allow that type to be set by the base. Check out this example:

public class Base
{
  public Base(Base child)
  { Child = child; }

  public Base Child { get; private set; }
}

public class Derived
{
 public Derived(Derived child) : base(child)
 {  }

 public new Derived Child 
 { get { return (Derived)base.Child; } }

}

If I could set Child on the Base class, I could have a casting problem in the Derived class. Another example:

Derived d = new Derived(someDerivedInstance);
Base b = d;
var c = b.Child;  // c is of type Base
var e = d.Child;  // e is of type Derived

I can't break any business rules by treating all of my Derived classes as Bases, it's just convenient to not type check and cast.

Marc
A: 

This is actually called member hiding. There are a couple of common scenarios where this can be appropriately used.

  • It allows you to work around versioning issues in which either the base or derived class author unwittingly creates a member name that collides with an existing identifier.
  • It can be used to simulate covariance on return types.

Regarding the first point...it is possible that an author of a base class could later add a member with the same name as an exisiting member in a derived class. The base class author may not have an knowledge of the derived classes and thus there is no expectation that she should avoid name collisions. C# supports the independent evolution of class hierarchies using the hiding mechanisms.

Regarding the second point...you may want a class to implement an interface that dictates a certain method signature and so you are locked into returning instances of a certain type only while at the same time you have subclassed that type and would really like for callers to see the concrete type instead. Consider this example.

public interface IFoo { }

public class ConcreteFoo { }

public abstract class Base
{
  private IFoo m_Foo;

  public Base(IFoo x) { m_Foo = x; }

  public IFoo Foo { get { return m_Foo; } }
}

public class Derived
{
  public Derived(ConcreteFoo x) : base(x) { }

  public new ConcreteFoo Foo { get { return (ConcreteFoo)base.Foo; } }
}
Brian Gideon
+1  A: 

What you are referring to is called Name Hiding. It is mostly a convenience feature. If you are inheriting from a class for which you do not control the source using new will let you change the behavior of a method even if it wasn't declared as virtual (or completely change the signature if it is virtual). The new keyword simply suppresses a compiler warning. You are basically informing the compiler that you are intentionally hiding the method from a parent class.

Delphi had the reintroduce keyword for the same reason.

What does this buy you other than a suppressed warning? Not a whole lot. You can't access the new method from a parent class. You can access it from an interface if your child class directly implements the interface (as apposed to inheriting it from its parent class). You can still call the parent class' member from the child. Any additional descendants of your class will inherit the new member rather than the one in the parent.

codeelegance
+3  A: 

I have just learned how to mask a base class member (using new)

FYI this feature is usually called "hiding" rather than "masking". I think of "masking" as clearing bits in a bit array.

am missing the point as to why I would want to do that.

Normally you don't want to. For some reasons to use and not use this feature, see my article on the subject from 2008:

http://blogs.msdn.com/b/ericlippert/archive/2008/05/21/method-hiding-apologia.aspx

Does masking provide us with a certain level of protection as is the case in using encapsulation?

No, it does not.

Eric Lippert