It\'s been years since I thought of this, but I am training some real juniors soon and need to explain what an object is to someone who doesn\'t know what it is.
B
I would try to compare the procedural programming paradigm with the OOP one. Even if your students are completely new to programming, I would show them some examples with 'primitives' and then the examples with objects. I would point the difference between a variable of a primitive type and an object of a class in that the type of the object may contain a number of variables (members). Of course at that point you should have mentioned functions, if they didn't already know them. In fact, in lesson one, I would explain the basic concepts of procedural programming (variables, types, functions) that are the basis for the fundamental concepts of OOP. After all, OOP is just a wrapper for procedural programming in itself.
After lesson one, along with explaining members of an object, you should explain methods as well. For "really junior students" I would focus on access levels, encapsulation and lastly on inheritance.
The real world examples, like car etc. can be used to show why it is good to have objects, but after exposing your students to the basic programming concepts. For your more talented students I would give out hints, like that an object is just an implicit argument to its methods, or that a member of an object is like a restricted global variable, or that an object is like a closure, etc. (that depends of course on your students and you need to make sure not to confuse them, so this last piece of advise is optional, of course :-) ).
One of the things I find many people get confused about in OOP are actual instances of an object. That you have the ability to create multiple instances of the same class, independent of one another, seems to blow peoples' minds. If you're going to go with the usual "physical object" analogy, make sure you talk about how you can have multiple instances of said objects and how they can interact with one another as well as with themselves.
For example, take the classic "car" example. Now you have your driver program "road" which has a "carCrash(Car car1, Car car2)" function. Explain how the objects interact with one another.
The only problem with analogies like this are that, in my experience anyway, they tend to break down when you start talking about static variables/functions. I guess what I'm trying to say is that no analogy is perfect, so try not to rely on them too much.
My experience as a self-learner is that I introduced a fair amount of trouble in my head with the concept of object as mapped to a "real entity" like animals and cars and so on. It forms your head in willing to find a realistic (as in "the real world") taxonomy in your business objects even when there's none, and it confuses you in finding unrealistic taxonomical classification that are instead useful for real OO design (eg. design patterns). Finally, it pushes you to the point that you fossilize in one "real world" taxonomy even if other "less real world" can exist and they are better.
In any OOP book you find that a square is a kind of rectangle, and so a square is represented as inherited by a rectangle, but we know that this approach is deeply flawed (I read a paper on that, don't remember where, but you can search about the "fragile base class problem" in google). Also, in some programming languages, you don't need OO taxonomy for interface inheritance (see my post on this regard).
So, my suggestion is: present it but be very careful how far you go, and eventually switch immediately from the "car and animals" examples to a less nice to present taxonomy. You can deeply flaw their understanding if you push it too far.
IMHO we must first get them interested in OOP before bombarding them with all the concepts in OOP. To make them get attracted towards OOP, explaining all the concepts in OOP or showing examples of cats and dogs will not work. You need to show them the advantages by comparing a problem solved the OOP and the non OOP way. Make sure you solve the problem first the non OOP way, highlight the disadvantages, use one of the concepts of OOP to solve it. It might probably employ only one concept of OOP, but if you are able to make them feel the advantage it holds over the other method, they would themselves be eager to explore more of OOP. You just need to point them in the right direction after that. Once they are familiar with the concepts, point them towards design pattern books like "Head first design patterns".
If I were trying to explain classes and objects to someone completely unfamiliar with programming, I would probably use something along the lines of the following:
A class is just a "recipe for a thing", the class is made of different types of "ingredients" that have different characteristics (i.e. PODs and functions/methods).
So, in that it only contains descriptions of a layout (building blocks) and functionality.
Ingredients may be of different type: "data" in that they contain actual data fields (think facts stored in variables/fields), and "action" in that they contain specific methods to do things.
Some ingredients may be secret, you may not want to share all ingredients or you may not want to share some specific ways of doing specific things with the recipe (encapsulation).
So, you as the cook have the possibility to restrict access to ingredients, so that users of your recipe have to adhere to your recipe and simply use "pre-canned" steps (methods) of doing things that you provide (without them necessarily knowing what it is about):
Some ingredients may be meant to be only internally visible (private access) because they are only really relevant to that specific instance/manifestation of the recipe/class, while others may also be meant to be accessible from recipes that are based on this recipe (think customizations), that derive from it (protected access).
And then there are ingredients that shall be generally visible and accessible to all users of the recipe (public), because they compose the "frontend" or "interface" of the final product (they don't necessarily need to know about internals/low level implementation stuff).
Once a class is actually used to implement a particular recipe, a new object is created (the class gets instantiated): A chocolate cake is just one manifestation/version of the chocolate cake recipe. There can be many other versions using the same "recipe".
If you were to combine multiple recipes (e.g. chocolate cake and lemon cake), you can create a new recipe that derives from both recipes, basically creating a completely new recipe that shares the characteristics of the original recipes (multiple inheritance).
By basing new recipes on existing ones using inheritance, changes in the original recipe can be directly imported into the new recipe. Similarly, having a common ancestor recipe (type/super class), means that its very properties (fields and methods) can be expected in all sub classes (inherited/child recipes), in other words a generic "chocolate cake recipe" might be used to create two new specialized versions of a chocolate cake: "white chocolate cake" and "dark chocolate cake", where the color of the chocolate merely becomes an attribute that may be configurable using a chocolate cake specific method like "setChocolateColor()".
If you want your recipe to provide a way for new recipes to override some components of your recipe, you can provide boilerplate actions (methods) that can be individually overriden (virtual inheritance).
I would use one example through the whole thing to build up the concept instead of jumping over unrelated examples.
That magical example would be GUI.
GUI made a lot of sense when I understood OOP after a lot of struggle.
A window is an 'object'. a button is nothing but a fancy way to say a rectangle drawn in a special way (abstraction). A window 'has' buttons. A hyperlink label 'is' a button. every Clickable thing on my Screen is a button (Interfaces). All buttons when clicked go to Stack overflow (inheritance). Except one button, which goes to Server fault (polymorphism).
And the hard part, 'Encapsulation' which is nothing but a fancy way to save the programmer from debugging :)
In the end I would stress that OOP is not the end of the world, If it does not make sense to think about something as an Object then it is NOT an Object. Because I have seen a programmer trying to build a mergesort class :D
Thanks,