Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why would you mask a base class member?

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.

like image 949
Asterix Avatar asked Aug 31 '10 14:08

Asterix


3 Answers

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.

like image 51
James Curran Avatar answered Sep 19 '22 09:09

James Curran


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.

like image 45
Philippe Leybaert Avatar answered Sep 20 '22 09:09

Philippe Leybaert


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.

like image 33
Marc Avatar answered Sep 21 '22 09:09

Marc