views:

126

answers:

4

I'm looking for bad examples of using inheritance. I'm not very creative so this was the best I could think of:

class Car : public Engine {}

A car has an engine, but it is not an engine.

This would probably work to explain the concept, but I believe there are more illustrative examples?

+5  A: 

The "classic" example ;-):

public class Stack extends Vector { 
    ...
}

A Stack is NOT a Vector.

If Stacks extend Vector, you are able to insert/delete at every given index, whereas you should only be allowed to add/delete elements by pushing/popping.

Helper Method
+1  A: 

Inheritance is very useful, but also breaks encapsulation. This means that your subclasses depend on implementation details of the superclass; if the superclass changes, your subclass may break. Here's an example in Java, from Effective Java by Josh Bloch:

public class InstrumentedHashSet<E> extends HashSet<E> {

   // number of attempted element insertions
   private int addCount = 0;

   public int getAddCount() {
      return addCount;
   }

   @Override public boolean addAll<Collection<? extends E> c) {
       addCount += c.size();
       return super.addAll(c);
   }
}

The problem is that HashSet's addAll() method uses its add() method internally, but doesn't document this. So if you try

InstrumentedHashSet<String> s = new InstrumentedHashSet<String>();
s.addAll(Arrays.asList("Snap", "Crackle", "Pop"));

you end up with a count of 6 instead of 3. In this particular case that isn't very harmful, but if you were adding a large collection or doing some other operation, it could be.

So, concrete classes are usually not a good idea to inherit from, unless they were designed to have subclasses.

Feanor
A: 

This have been debated for years, and you'll find a lot of materials/talks referencing the problem on google.

public class Square extends Rectangle { 
    ...
}

Perhaps not very surprising though, a square should not inherit from a rectangle.

nos
I did not find good example on google, that's why I'm asking.
mafutrct
nos
I have yet to see a square that wasn't a rectangle. Can you draw me one?
Gabe
@Gabe In the real world, sure. In OO, no. The simple explanation for the troubles you'll get is here http://cafe.elharo.com/programming/a-square-is-not-a-rectangle/
nos
nos: Why does OO have *to* not model the real world? In the real world, changing the size of a rectangle gives you a *different* rectangle. Just make your implementation not let you change the size of an existing Rectangle. Or change your contract so that the client knows that there could be size or aspect ratio restrictions.
Gabe
@Gabe . I have no idea what you're getting at, did you read that article ? In the real world, changing the aspect or one of the lengths of a square makes it a rectangle. Modelling that in an OO language is ofcourse possible, but it creates a lot of trouble if you do it by having Square inherit from Rectangle in most OO languages if you do it the traditional way (Traditional way here means e.g. not making those classes immutable)
nos
nos: The problem is the author's fundamental assumption that changing the width should not affect the height (even though he has no problem with affecting the area or perimeter). This assumption precludes the ability for a rectangle to have a fixed aspect ratio. `Square` is just a subclass of `Rectangle` that has a fixed aspect ratio of 1:1. `HDTV` is a subclass of `Rectangle` that has a fixed aspect ratio of 16:9.
Gabe
@gabe That's not the issue. The OP question is what are examples of bad use inheritance. Having Square extend Rectangle is bad, given you provide setHeight/setWidth methods and do this the traditional way. If you e.g. don't provide a setWidth/setHeight method, or anything else that lets you manipulate a Rectangle in a way that makes a Square suddenly not become a Square anymore - the issue is gone.
nos
nos: I'm looking at your post, and all it says is that "not very surprising though, a square should not inherit from a rectangle". I find it quite surprising because absent an explanation, there is no *per se* reason a square could not be a rectangle. It's only when you implement it wrong that it's a bad example, but then it's a bad example of implementation, and any example can be implemented poorly.
Gabe
@gabe , maybe you're right, however particular problem here "is a Square a rectangle" is a common one. It has been discussed, not without reason, for a *very* long time, and it appears in many books. I'm not sure there's a conclusion if it makes sense to have Square inherit from Rectangle. There's probably some ways to do it the right way, and many ways to do it the wrong way, but are there many reasons to implement this as an inheritance chain in code ? There are many pitfalls you need to think about, and that many don't that's not obvious at first - and that was the point of the exercise.
nos
+4  A: 

Use pretty much any example that uses inheritance without regard to the behavior of the base class.

A classic example is the relationship between Square and Rectangle. Sure, in mathematics, a square is a type of a rectangle. However, in software design, a square doesn't behave like a rectangle:

public class Rectangle 
{
    public virtual int Width  { get; set; }
    public virtual int Height { get; set; }
}

public class Square : Rectangle
{
    public override int Width
    {
        get { return base.Width; }
        set
        {
            base.Width = value;
            base.Height = value;
        }
    }

    public override int Height
    {
        get { return base.Height; }
        set
        {
            base.Height= value;
            base.Width = value;
        }
    }
}

If another class, Client, needs a Rectangle but gets a Square, Client will break because it expects its Rectangle to have a Width and Height that don't affect each other.

This only breaks down because Rectangle is mutable.
Lee
I agree with Lee -- in the abstract sense a Square `is a` Rectangle, it's only your particular implementation that makes it invalid.
Gabe
Jeff: You could just change the contract so that the client doesn't expect the `Width` and `Height` to have no effect on each other.
Gabe
I agree with Lee, too. This is just an example that I've seen in a few OOP books. In every case, the author leaves immutability out of the example. (Sorry for the late response.)