views:

230

answers:

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.

+4  A: 

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
+8  A: 

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
Your reflection solution. That would throw a run-time error, not compile time, correct?
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
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.
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
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
ok. cool.I've decided to make Foo abstract, and create an 'emptyFoo' class for this specific method.
an 'emptyFoo' subclass of Foo, that is.
+1  A: 

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
+1  A: 

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
+3  A: 

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
+1 - Nice details, and another great way to word the concepts.
Reed Copsey
Thanks. I find it helps to give a learner several ways to read the same thing; one, r the combination, may "click".
tpdi
If it's protected, shouldn't bar have access to it?
Christopher W. Allen-Poole
Yeah, Bar can call a protected member of Foo; but users of Bar can't. That's the distinction.
tpdi
A: 

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.