LorenzoGatti has a point, that the Tank and Cannon example may not be a very good one here. In most cases having a distinct Cannon class is not necessary. For most use cases in games, you are breaking down the object into more parts than you need to.
Sure - you can always simplify and flatten things down if you like. I mean, on the other extreme, you could represent all Actors as the same class, have a bunch of flags represent the different things your Actor might want to do (canShoot, canFly, canCarryPerson, isPerson) and handle all the code in one place but vary the models or sprites or whatever visual data you have. Obviously a balance between the two extremes needs to be found and the question one needs to ask is what level of flexibility do you need and what data do each of your game systems need. If you have vehicles that drive with reasonably accurate physics (so any game where driving is a big focus), your physics engine might indeed simulate wheels and your game logic might indeed have an engine that handles how it drives (or at the least is a pure data container with all the properties representing the engine: power, weight, whatever) - the point, as I see it, of component entity systems is that the components can be simple data containers if that's all you need, or they can have systems with complex logic associated and components in themselves are extremely cheap (eg they could be allocated from a memory pool, they could be cache line aligned, the processing loop could prefetch...).
But that's besides the point I was implying in my previous post - obviously the example was a contrived one. The real point wasn't even specific to game programming, but rather that in my opinion composition is much more natural to inheritance in that with real world objects, entities can often be classified as many things (I'm a living thing, I'm human, I'm a programmer, whatever...) that are dependant on the entities state (either internal or external) and that entities are composed of many things. Also often removal of some of these things does not cause the entity to lose a is-a relationship, removal of other things might (but exactly which things may not be well defined - if I kept removing parts of my body, when do I stop being human?). Then I went and mentioned some ideas which could be used to take the concept even further.
I think that this idea is just as applicable in software outside of games too.
But obviously, as you imply, a balance must be struck to find the level of abstraction that best fits the problem space - but isn't this always the case, regardless of how the problem is being modeled (OO or otherwise)?