6

I have a base class Foo that is concrete and contains 30 methods which are relevant to its subclasses.

Now I've come across a situation that is specific only to the base class,and I want to create a method that cannot be inherited, is this possible?

Class Foo 
{
   /* ... inheritable methods ... */

   /* non-inheritable method */
   public bool FooSpecificMethod()
   { 
      return true;
   } 
}

Class Bar : Foo
{
    /* Bar specific methods */
}

var bar = new Bar();
bar.FooSpecificMethod(); /* is there any way to get this to throw compiler error */

EDIT

I'm not sure if I was clear originally.

I do understand the principles of inheritance, and I understand the Liskov substitution principle. In this case there is a single exception that ONLY deals with the 'un-inherited' case, and so I did not want to create an 'uninheritedFoo' subclass.

I was asking if it is technically possible to create a situation where foo.FooSpecificMethod() is a valid and publicly accessible method, but subclassoffoo.FooSpecificMethod() throws a compiler error.

Essentially I want a sealed method on an unsealed class.

DevinB
  • 8,231
  • 9
  • 44
  • 54

11 Answers11

11

I would rethink the need for this.

If you are using inheritance, you are suggesting that "Bar" IS A "Foo". If "Bar" is always a "Foo", methods that work on "Foo" should also work on "Bar".

If this isn't the case, I would rework this as a private method. Publically, Bar should always be a Foo.


Just to take this one step further -

If you could do this, things would get very complicated. You could have situations where:

Foo myBar = new Bar(); // This is legal
myBar.FooSpecificMethod(); // What should this do?  
                           // It's declared a Foo, but is acutally a Bar

You can actually force this behavior using reflection, though. I think it's a bad idea, but FooSpecificMethod() could check the type of this, and if it isn't typeof(Foo), throw an exception. This would be very confusing, and have a very bad smell.


Edit in response to question's edit:

There is no way for the compiler to enforce what you are asking. If you really want to force the compiler to check this, and prevent this, you really should consider making Foo a sealed class. You could use other extension methods than subclassing in this case.

For example, you might want to consider using events or delegates to extend the behavior instead of allowing the object to be subclasses.

Trying to do what you are accomplishing is basically trying to prevent the main goals of inheritance.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • Your reflection solution. That would throw a run-time error, not compile time, correct? – DevinB Apr 08 '09 at 12:30
  • Yes. You could have FooSpecificMethod throw a runtime error if the caller's type is not a Foo (ie: if you pass a Bar object in). This would allow myBar.FooSpecificMethod above to compile, but throw at runtime, since it's actually a typeof(Bar) and not typeof(Foo). – Reed Copsey Apr 08 '09 at 15:02
  • Foo myBar = new Bar(); This creates the memory allocation needed for a Bar, but the program is given a Foo variable. The Bar is implicitly CAST to a Foo. It is the same as saying Foo myBar = (Foo)(new Bar()); So after that line executes, there is no Bar in existence anymore. only a Foo. – DevinB Apr 08 '09 at 19:41
  • No, not true. There is a Bar in memory, allocated as a bar, but it's being USED as a Foo. If you use reflection, and get the type of myBar, it will be a Bar still. If you want to see, just break in the debugger, and check :) – Reed Copsey Apr 08 '09 at 19:43
  • If you create a new Bar(), it doesn't matter what you return. You can assign it to a Foo, or even a System.Object, but it's still (and always will remain) a Bar object. – Reed Copsey Apr 08 '09 at 19:45
  • ok. cool. I've decided to make Foo abstract, and create an 'emptyFoo' class for this specific method. – DevinB Apr 08 '09 at 19:52
  • an 'emptyFoo' subclass of Foo, that is. – DevinB Apr 08 '09 at 20:11
6

Brian's right about Liskov Substitution (upmodded). And Reed's right about "is-a" (also upmodded); in fact they're both telling you the same thing.

Your public methods are a contract with users of your class Foo, saying that, "you can always" call those methods on Foo.

Subclassing Foo means that you're saying that a Subclass, e.g. Bar, is always acceptable to use where a Foo could be used. In particular, it means you inherit not (necessarily) Foo's implementation (you can override that, or Foo may be abstract and give no particular implementation for a method).

Inheritance of implementation (if any) is a detail; what you're really inheriting is the public interface, the contract, the promise to users that a Bar can be used like a Foo.

Indeed, they may never even know they have a Bar, not a Foo: if I make a FooFactory, and I write its Foo* getAFoo() to return a pointer to a Bar, they may never know, and sholdn't have to.

When you break that contract, you break Object Orientation. (And the Java Collection classes, by throwing NotSupported exceptions, entirely break OO -- users can no longer use so-called subclasses polymorphically. That's poor, poor design, which has caused major headaches for many many Java users, not something to emulate.)

If there's a public method that Foo subclasses can't use, then that method shouldn't be in Foo, it should be in a Foo subclass, and the other subclasses should derive from Foo.

Now, that does NOT mean that all methods in Foo should be callable on subclasses. No, I'm not contradicting myself. Non-public methods are not part of a class's public interface.

If you want a method in Foo that can't be called on Bar, and shouldn't be publicly callable in Foo, then make that method private or protected.

tpdi
  • 34,554
  • 11
  • 80
  • 120
  • +1 - Nice details, and another great way to word the concepts. – Reed Copsey Apr 08 '09 at 00:05
  • Thanks. I find it helps to give a learner several ways to read the same thing; one, r the combination, may "click". – tpdi Apr 08 '09 at 00:11
  • If it's protected, shouldn't bar have access to it? – cwallenpoole Apr 08 '09 at 12:32
  • Yeah, Bar can call a protected member of Foo; but users of Bar can't. That's the distinction. – tpdi Apr 08 '09 at 14:11
  • In languages with single-inheritance, the LSP only applies to members which can be accessed by other instances. If none of the classes which would be able to access a protected member in outside instances does so, the LSP does not require that the member be available to derived classes. Given `FortExplorer:Car` and `ToyotaPrius:Car`, a reference of type `Car` might refer to a `FordExplorer` or `ToyotaPrius`; within `FordExplorer`, however, though the nominal type of `base` is `Car`, but it's guaranteed *not* to refer to a `ToyotaPrius` (nor anything else that not derived from `FordExplorer`). – supercat Jul 27 '13 at 18:23
4

No, this would violate the Liskov substitution principle.

Pragmatically, you can either have it "throw NotImplementedException()" in Bar, or remove the method from Foo and move it down to the subclasses to which it applies.

Brian
  • 117,631
  • 17
  • 236
  • 300
  • There are two cases where it would not violate LSP: (1) If the member is `protected`, and code in or above the present class which could access that member in outside instances doesn't do so; (2) If the base-class contract specifically states that some derived classes may not implement that member usefully. Hiding a public member of a base class won't prevent code from calling it--it will just make it more cumbersome. One should thus refrain from doing so if calling code would need that member. If the member is useless anyway. however, there's no reason it should be easy to call. – supercat Jul 27 '13 at 18:37
2

Making the function private will prevent it from being called by the subclasses directly.

If you are talking about virtual functions that you do not want to be overloaded, marking the function as sealed at the point that you want to "lock" the function works.

Even if it is a private function, it could still be called by reflection.

You could also declare the function on an interface, and explicitly implement the interface on the class, which would force you to cast it to the interface to use the function.

Jason Coyne
  • 6,509
  • 8
  • 40
  • 70
1

I have been trying to achieve this myself and came across this post which has some great answers without achieving what the poster was after, but there is a way to enforce this. You need to override the existing method and then use the Obsolete attribute. Setting the Obsolete attribute's error property to true will prevent compile.

Class Foo 
{
   /* ... inheritable methods ... */

   /* non-inheritable method */
   public bool FooSpecificMethod()
   { 
      return true;
   } 
}

Class Bar : Foo
{
    /* Bar specific methods */

   [Obsolete("Don't use this for whatever reason", true)]//true triggers the compiler error
   public new bool FooSpecificMethod()
   { 
      return true;
   } 
}

var bar = new Bar();
bar.FooSpecificMethod(); /* this now throws a compiler error */
1

You could make a private function, and then call it using reflection. Probably a little overboard. Anyway, just put the function in your base class, along with comments saying it should only be called from the base class. Maybe even those nice /// comments that show up with intellisense. Then, you might get a bug, but then well, you'll always get bugs, and the best you can do is document this situation to try and avoid it.

Kibbee
  • 65,369
  • 27
  • 142
  • 182
0

There are two reasons a derived class may hide base-class members without violating the Liskov Substitution Principle:

  1. If the member in question is `protected`, it essentially represents a contract only between the parent class and the derived class. As such, it does not impose any obligations on the derived class, except as required by the contract with the parent. If public members of the base class relies upon some non-public particular member of outside instances having some particular meaning, a derived class which changes the meaning of that member could violate LSP even though the member itself is not public, since changing its meaning could alter the behavior of the public members which use it. In cases where a base class defines a protected member but does not use it, however, a derived class could do anything it likes with that member without violating LSP. A key thing to understand with protected members is that the reason a `ToyotaCar` should not alter the semantics of public members of `Car` is that a reference to a `ToyotaCar` might be given to code which is expecting a `Car` rather than a `ToyotaCar`. On the other hand, if `ToyotaCar` alters the behavior of a protected method of `Car` in a fashion which isn't exposed by any public members, the only code which could notice such alteration is code which is within either `ToyotaCar` or a derivative thereof, and such code is going to know that it has a `ToyotaCar`. Code which is in some other `Car` derivative (e.g. a `FordCar`) can access the protected members of `Car`, but is guaranteed *not* to access those methods on an instance of `ToyotaCar`.
  2. Sometimes it is useful to have a base type or interface expose a number of members which will not all be applicable to every implementing type. While the Interface Segregation Principle would suggest that one should avoid "kitchen-sink" interfaces, there are cases where such interfaces may be more practical than any alternative. For example, some kinds of a "stream" class might support different handshake modes, but other types would not. If references streams will be passed through code that won't care about handshaking, it may be easier to have a Stream class include a handshake-selection property which may or may not be usable, than to require code to try casting a passed-in reference to `IHandshakeSelector` and set `IHandshakeSelector.HandshakeMode` if so. On the other hand, if a particular stream class would behave identically for all handshake modes except `XonXoff`, which would throw an exception if code tries to set that, it may make sense for that class to hide the `HandshakeMode` property.

I would posit that while base-class member hiding is often a sign of bad design, there are cases where hiding base-class members would be more appropriate than leaving them exposed; if a derived class cannot possibly use a protected method correctly (as would be the case with the MemberwiseClone method available to derivatives of List<T>) there's no reason to have it exposed. Unfortunately, there's no completely clean way of hiding such members. The best one can do is declare a public member of the same name (using a "new" modifier) which would block off all access to the base-class member. For example, code could define a nested public static class named MemberwiseClone with no members. The EditorBrowseable attribute could be used to prevent Intellisense from showing that nested class, but even if code did try to use that class, it has no members, and one cannot create a storage location of that type, so it should be pretty harmless.

supercat
  • 77,689
  • 9
  • 166
  • 211
0

You should consider Composition [http://en.wikipedia.org/wiki/Composite_pattern} over inheritance if you want to achieve what you are trying to do and expose methods from the private object (i.e. the one you are currently inheriting from).

Denis
  • 11,796
  • 16
  • 88
  • 150
0

As others have pointed out, this is not possible, and most importantly, it shouldn't be necessary.

I came across the same problem when I had the following structure:
- A parent class with properties of child classes.
- The child classes would expose different properties, but all had the same initialisation procedure, so I put the code in the parent class.

public class Parent
{
    public CHILD1 Child1;
    public CHILD2 Child2;

    public Parent(params args){
        Child1 = new CHILD1(arg1, arg2);
        Child2 = new CHILD2(arg1, arg2);
    }
    //split here
    public Parent(object arg1, object arg2) {
        PropertyInfo[] list = this.GetType().GetProperties();
        foreach (var pi in list) {
            pi.SetValue(this, BL.Method(arg1, arg2, this.GetType().Name, pi.Name) // get data
        }
    }
}

public class CHILD1 : Parent
{
    public CHILD1(object arg1, object arg2) : base(arg1, arg2) { }

    public object C1Property1 { get; set; }
    public object C1Property2 { get; set; }
    // ..
}

public class CHILD2 : Parent
{
    public CHILD2(object arg1, object arg2) : base(arg1, arg2) { }

    public object C2Property1 { get; set; }
    public object C2Property2 { get; set; }
    // ..
}

Now I could call parent.Child1.C1Property1. But the code would also allow a call of the following: parent.Child1.Child1.Property1, which wouldn't make sense and result in an exception because the Child1.Child1 property would always be null.

In order to fix this, all I had to do was split the code of the parent class into two classes:

  • One holding the Child properties and calling child constructors
  • and one with the constructor logic to fill the properties.
Damian Vogel
  • 1,050
  • 1
  • 13
  • 19
0

Perhaps you could simply create it as a virtual method on the parent class and then override it, throwing a NotImplementedException or something similar, on the child class that inherited it.

Also, but only if you're willing to put up with some spaghetti, you could put the method's signature in an interface and then have all the classes that'll require such method implement it. The downside is you'll have to declare the same method in all those children.

I'm not sure if it's even possible, but maybe an extension method could be written for that interface?

Keep in mind that these are all violations of OOP's encapsulation principle, albeit minor, which makes them all the more fun.

0

The solution I ended up using was creating a public inner inherited class. That way it is able to access the private variables of the baseclass (as it needs to) and I don't need to expose publicly any of those private variables or functions (which I don't want to).

Thanks so much for all your advice, it caused me to rethink exactly what I needed from this arrangement.

DevinB
  • 8,231
  • 9
  • 44
  • 54