Mis Using Inheritance

Using inheritance to utilize base class members even when there is no clear 'type of' relationship.

Why is this misusing inheritance? If access is needed to base class members, why not provide it?

Consider the following PseudoCode

  class Bird {
    virtual fly() { flapWings(); }
    virtual feed { digForGrubs(); } 
  }

class Pig extends Bird { virtual feed { super.digForGrubs(); rootForTruffles(); } }

Pig p = new Pig();

p.feed(); // okay p.fly(); // pigs fly?!!?

You might consider this overly contrived, but I have seen cases in real code that were nearly as nonsensical.

I interpreted it as using trees when the change-pattern is not really tree-shaped, or classic "subtyping" is just not appropriate. (See links below.)

Isn't this merely bad class definition? I am not sure how this is anything that is peculiar to Inheritance.

This is using inheritance to get the superclass behavior when there is no clear type-of relationship. It really does happen that programmers who are unfamiliar with inheritance would not see this as a bad class definition because they see that Pig and Bird both feed and they need something on Bird. The inexperienced programmer may think in terms of type-of feeding (A Pig is a type-of thing that feeds by digging for grubs) and not see the larger picture that a Pig is not a subclass of Bird. Granted, this is extremely contrived, but there are real cases where a programmer has subclassed a totally inappropriate parent just to get some behavior. Perhaps refactoring, (class Grubfeeder?), composition, and delegation need to be stressed more in OO design. -- StevenNewton

java.util.Stack is a very good example of this. It inherits from Vector, because it "needs" certain implementation details from Vector. But a stack is not a vector at all, and this means you can randomly access elements of the stack.

It's really a language smell, because Java couples ImplementationInheritance and interface inheritance. You can have the latter without the former (through interfaces), but you can't have the former without the latter. SmallTalk has the same problem, but it's less evident because "private" is just a convention in SmallTalk. C++ gives you private inheritance, where you'd get digForGrubs() but wouldn't expose fly() or feed() to other classes. And the issue doesn't even come up in CommonLisp/Dylan/Cecil, because methods there don't belong to classes. -- JonathanTang

I sometimes find "sets" useful for these kinds of things. They both belong to the set of "Grubfeeder" in this example. Sets are not as rigid as hierarchies, and thus perhaps require less up-front planning because of that. I also question whether MultipleInheritance is a satisfactory solution for giving us good set management. For one, sets can return "multiple hits", while MI is usually limited to just one.

The example does not support the premise. The premise was "Using inheritance to utilize base class members ..." while the example concerned overriding base class methods. What is intended to be discussed here?

Oh my, I thought it was something most third-generation heirs were prone to do with Granddad's money ...

Oh, you mean investing it on www.petfood.com? :-)
Another example that I see more often:

  class Animal {
    virtual bool feed() { chew(); swallow(); return true;} 
    virtual bool fly()  { flap(); return true; }
    virtual bool swim() { dive(); surface(); return true; }
  };

class Pig : public Animal { virtual bool fly() { return false;} // A pig is an animal that can't fly };

class Bird : public Animal { virtual bool swim() { return false; } // A bird is an animal that can't swim };

class Penguin : public Bird { // Shoot; in version 3.1 we have to support penguins?! virtual bool swim() { dive(); return true; } // Restore original behavior virtual bool fly() { return false; } // Current rev of penguin crashes when it flies // don't know why, so disable it };

And then we wonder why our penguins keep drowning in the field. --TimLesher


See Also: ClassicOoAntiPatterns, LimitsOfHierarchies, ThereAreNoTypes, DeltaIsolation, LiskovSubstitutionPrinciple
CategoryPolymorphism

EditText of this page (last edited October 22, 2007) or FindPage with title or text search