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.