There’s a rule-of-thumb I’ve found about OOP where you want to use composition when extending data, and you want to use inheritance when extending behaviors. The zoo animal metaphor that you often see used in teaching inheritance (lions are animals, simba is a lion all animals have a length, but lions also have claws etc.) is a bad perspective and you should never use inheritance to model a problem like that in the r…
See https://news.ycombinator.com/item?id=39999644
It's very useful when a base class provides an incomplete implementation, and the child class completes the implementation.
Sometimes I use it when testing, where the child class alters some behavior in a way that mocking can't do correctly.
In C# / Java, inheritance is used for setting up filters for exceptions