Inheritance is the most overused concept in OO. It was the new toy after coming from C and each “good” C++ program had to declare many classes and complicated inheritance hierachies.

It is always useful to use inheritance only when you can say “A is a B”, then A might be a candidate for inheriting from B. In C++ you have multiple inheritance amd when you are willing to go through the hell of destructor logic, nothing keeps you from working with this definition only.

The anti use of inheritance is sometimes called “duck-typing”. It quaks, thus it must be a duck, but actually you quaking object is only showing the behavior of a duck, thus injecting the behavior of quaking is preferable of sub-typing. Some language have the concept of traits or mixins that help implementing such a method injection very cleanly.

Inheritance is a powerful tool and in most OO languages a scare resource: You can inherit only from one class. What happens if inheritance is overused are “combinatorial” hierachies where the class diagramm looks like a balanced tree. This introduces invariably redundance and should thus be avoided.

The most dangerous use of inheritance is insufficient foresight, consider a base class for creation and for alteration. All your action inherit from the one or the other - everything is clean up to the moment where you start specializing your actions. Now the combinatorial hierachies evolve - whereever you split an action from creation, the corresponding action on alteration will follow. After some actions have 5 and more variants you realize that creation and alteration hadn’t been proper types, just behavioral interface - injecting their behavior into a single hierachy of your action would have been much easier and created less redundance