- Common operations between classes, operating on common data, but requiring an external API (so composition is a pain because you would have to proxy those actions to the member.)
- Restricting/specifying the types of objects you can store in a container if you are programming in a language/codebase that cares about that (incl. the C++ "definitely has the vtable I want".)
And maybe that's it? I guess all the taxonomy talk might be useful in the first hour of learning about inheritance, but after that I think the analogy should give way to more concrete "what are the code and data doing?" angle.
It’s like if someone took the cascading idea of CSS and decided “this works so well for UI styling, let’s build a language paradigm out of it and convince people they need to express every problem in terms of it.”
I think it's a classic case of teaching people the answer before the question.
Animal examples explain what types and subtypes are, but the thing that warrants explaining is why and when it's useful to separate things into types and subtypes, and animal examples are terrible for that. If someone asks "should Cat and Dog inherit from Quadruped? Mammal? Pet?" there's no useful answer.
Classes are a neat way of hiding implementation detail behind a mini-api that has reasonable code-hygiene benefits and works well in a team setting. None of these things have anything in common with meowing cats.
There was a classic on HN a while ago [1] illustrating how blindly guessing an OOP hierarchy for a problem isn't going to help. Throw that at a learner without thinking too hard, and they are going to question what the benefits of OOP even are - it doesn't always simplify a problem.
[1] https://www.quora.com/Is-abstraction-overrated-in-programmin...