I am trying to wrap my head around object oriented programming.
My understanding is that we have objects so we can design our programs to mirror real-life objects.
Most human languages follow a sentence structure (For simple statements) of Subject Verb Object
In OOP languages like c++, not entirely ironically, the object is the object, and it comes first, so the normal order is reversed:
So this is the 'basic' pattern in c++ :-
object.verb( subject );
This is actually rubbish. Most classes are designed with a subject.verb(object) interface. Knowledge of SVO however does allow one to test whether or not a class interface has been designed to be the correct way around (in this case, it has not).
That said, there are a large number of human languages that are naturally OVS, or some other variant where the typical english order is reversed. When dealing with internationally developed software other developers might have a different idea as to the correct and normal order of subjects, and objects in a simple statement.
Simply mirroring real-world objects is rarely a good idea. To borrow from a classic example - software that controls a coffeemaker is not about coffee beans and hot water - it's about making coffee.
You need to find the underlying abstraction to your real-world problem, not just copy nouns into object hierarchies.
If your apple derives from fruit, does it add any interesting behavior? Is the hierarchy really needed? Inheritance adds a level of complexity to your software and anything increasing complexity is bad. Your software is just a bit harder to follow and understand, there's just a bit more to cover in your test and the likelihood of a bug is just a tiny bit larger.
I find OOP is more about the whitespace - what you are leaving out is more important.
Assuming you were, say, writing a hungry people simulator, then I think it would make much more sense to, as you say, have a Human::Eat(Fruit f)
function. Your Fruit might not have methods since Fruit doesn't do much on it's own, but it might have a calories
property, and so on.
Should a fruit object rather be passed to a human object which has a Eat() function?
Yes.
But program objects are generally more abstract than this naive example. In the real world of computer programming, objects like fruit and humans would generally be represented as attributes in a database. The consumption and manipulation of such data would be done in programming objects.
I always find examples using 'animals' or 'fruit' counter-intuitive. People are difficult objects to model, and it's unlikey that you'll encounter applications with the same requirements.
Using the concept of anthropomorphisation can really help assign reponsibilities. Basically, imagine that your object is a person (I typically sketch them with a face and limbs during design sessions).
Now you can ask these questions about your object:
"Object Thinking" by David West is a good book to read on the topic.
I don't think we should try to "mirror real-life objects". I think it's more of finding real life objects that closely resemble the behavior being modeled within the context of the system (domain). A Fruit class in a game where you slice fruit for points might have drastically different behaviors and attributes than the Fruit class in a game where a character runs around collecting fruits for points; or a simulation of people eating fruits. Assigning behaviors to classes named after real life objects makes it easier to assume the behavior of code modules and speculate on their interactions.