Though it may appear a minor distinction, the difference between an object and a class is something which developers seem to misunderstand all the time. The question often comes up in interview situations, so I figured I’d try to clear this one up.
Before we get started, if you’re an experienced software engineer you may find the examples here a little too simplistic. My purpose here is to explain what objects and classes are, not demonstrate how clever I can be in doing so, and so I’ll be keeping it simple…
An Object is…
An object, in software engineering, is nothing more than a piece of data.
For those of you yelling “What about methods? or properties?…” I’ll come to that…
When we talk about an object, we’re actually talking about an abstract representation of some ‘thing’. This thing could be a real world object such as a car, or a cup, or it could be an imaginary object, such as a unicorn or a pixie. Similarly the ‘thing’ could be virtual, for example, a button on your screen is not a real button, it’s a virtual button, but it still counts as a thing. Anything which you can call a ‘thing’ can be represented inside computer memory as data, and in that case would count as an object.
Now, think of a thing. Any thing you like, perhaps your favorite thing. How would you describe that thing? As you describe something, you do so by providing various descriptive properties of it. For example, if your thing was a cup, you might state it’s color, that it has a handle, that it’s 5-inches tall, and so on. Similarly, objects in software have properties and again, these properties are merely data.
So lets look at what a representation of a cup might look like when expressed as data in a computers memory.
05 02 03
Hmm, that doesn’t look like much. It’s just three numbers. Well, remember that computers only understand numbers. A computer has no concept of what a cup is, or what a car is. When we represent an object to a computer, it sees only the numbers. In this case we’re looking at a cup which has a height of 5 inches (05), a radius of 2 inches (02), and is colored by the number 3 (03) which for the sake of this discussion we’ll say is blue.
Now lets take a look at what a car might look like when expressed as data in a computers memory.
05 02 03
At this point you might be asking, “Hey, what are you trying to pull here? That’s not a car, it’s clearly a cup?!” – Well suppose you had a car with five doors (four+trunk), a two liter engine, and it’s also blue. To a computer your could represent that information using the same three numbers as our cup above. Again, the computer has no idea what a car or a cup is, it just sees numbers.
So how do we tell the difference between a car and a cup? That’s where classes come in…
A Class is…
The word Class is no accident. Class is short for “classification” and it’s what we use to distinguish between different types of object. Here are classes for our cup and our car, written using pascal-like psudo code.
Cup = class property Height_In_Inches: number; property Radius_In_Inches: number; property Color: color; end; Car = class property Doors: number; property Liters: number; property Color: color; end;
One of the most important things to notice here is that the classes are written in source-code form, and this is the only place you’ll ever see a class, in source code! There is no such thing as a class in a running computer program, there are only objects! To explain, lets take a look at our object in memory again, but this time, we’ll give the memory some addresses…
This is what our Cup or Car object looks like in memory. We tell the compiler how to classify this piece of memory as, for example, a Cup by defining a class. From now on, the compiler will let us refer to the first memory location as “Height_In_Inches” rather than by it’s actual numerical value “$0001”, because we’ve told the compiler that this piece of memory is a cup, and “Height_In_Inches” is the first property of that class.
By allowing us to classify our object as a Cup, the compiler is simply giving us the ability to label the parts of the object, but those labels are not useful to the program when it’s running, so the compiler strips them out and replaces them with something that the computer can understand, numbers!
When I described what an object is above, I told you that it’s a piece of data that describes some object through it’s properties (on more or less words). Well objects have not only form but also function. That-is, a car may be described by its color and number of doors, but it may also be driven. We interact with a car by selecting gears, or pushing it’s accelerator. Well, similarly in software, we can interact with objects through the use of methods.
A method is, more-or-less, nothing more than a function, but it’s a function which may be written with the assumption that it is associated either with some object, or with some class. When they are associated with an object, they are virtual methods, and when they are associated with a class they are static methods. Lets look at virtual methods first…
Virtual Methods are just functions, like any other, but with one distinct difference. Virtual methods have a secret hidden parameter, which you never need to pass in when calling the method, but it’s there all the same. This parameter is a reference to an object.
So, say we have two car objects, we’ll call them Car1 and Car2. Each of these two objects is represented by a Car class, and the Car class has a method named ‘SwitchGears’. Now suppose you call the method like this (psudo-code again)…
Car1.SwitchGears( Forward );
What the compiler actually generates is something more akin to this…
SwitchGears( Car1, Forward );
The Car1 object is being passed as a parameter to the method! From within the method you can usually address this object using the reserved variable name of ‘Self’ or ‘this’. So if you call “Self.ChangeGearLight( Forward )” from within the method, then if that method is called on Car1 it will switch Car1 into the forward gear and set the gear indicator light for Car1, but will not affect any other objects of class Car. (So Car2 is not affected).
Now what’s important here is to understand the following…
When your compiler generates the binary code for the SwitchGears() method, it will only create that binary code once. Period. In fact, it would be an inefficient compiler that did generate the code several times, or caused code to be instanced at run time.
I once had a discussion with an engineer that believed that when a class is used to instance an object, an entirely new copy of each of the classes methods would be generated. This is simply not true. The compiler will generate the method once, and then make sure that an object is passed in as the secret hidden parameter.
To continue what developed into an argument.. “Then what about event callbacks? When I assign Car1.HandleAccelerate to an event call-back, that’s different to when I assign Car2.HandleAccelerate!” – This is true, but there’s still only one instance of HandleAccelerate. What’s happening is the compiler is generating something called a ‘v-table’ on the end of each car object. The v-table (vector table) for Car1 contains a vector which calls HandleAccelerate and passes in the secret parameter reference to Car1. The v-table for Car2 contains a vector to call HandleAccelerate and passes in the secret parameter reference to Car2, and so on. When you assign Car1.HandleAccelerate to a callback, you’re actually assigning the vector from the v-table, not the address of the HandleAccelerate method it’s self.
(Often referred to as Class methods. In particular in Delphi where the static keyword has another meaning)
Static methods are still methods which are associated with a class, but not an object. That-is, unlike virtual methods, no secret parameter is passed in to reference an object, the method stands-alone and does not need an object to operate on.
You can think of a constructor as a kind of static method.
Let’s see an example..
When we call Car.Create, we are referring to the Create method of the Car class. We haven’t passed in a reference to an object (i.e. Car1, Car2 etc) and the compiler hasn’t secretly done this for us, but instead, we’ve just called a method which assumes it’s a method of the Car class.
This is because we’re not trying to perform an operation on an existing object, but rather, we’re trying to create an object based on the Car class definition. So there would be little point in the compiler passing an object reference in to the Create method, see?
Now assuming Create is our constructor, because it is the Create method of the Car class, it’ll take a look at the Car class and decide how many bytes of memory are required to store the properties of a car object, and it’ll reserve that amount of memory for us. (Note: It’ll include enough memory for the v-table too).
To confuse you…
It’s an unfortunate but simple fact that these concepts become quite confusing. Here are some examples of confusion:
- An engineer might refer to an object as an instance, but (s)he means the same thing. An instance of a class IS an object.
- I’ve not touched on inheritance in this post because, well frankly it’s not relevant to the question, but also it confuses things further. Many object oriented frameworks have a hierarchy of inherited classes which root to a class named ‘Object’. Delphi for example has TObject which is actually a class, but which is the root of the hierarchy of classes. Why didn’t Delphi root to TClass? because TClass means something else, it’s a reference to a class definition!
- Many engineers will use the words ‘object’ and ‘class’ synonymously, and though they’re technically wrong to do so, trust me, you don’t need the argument that will follow if you try correcting them.
- Different compilers and different frameworks sometimes misuse the terminology differently. I mean, they all misuse it somewhere, but none can agree on a standard misuse.
- Oh, and class is nothing to do with the room you’re educated in, nor your social standing.
I hope this short post helps to clear up some of the confusion, but, don’t expect it to get you past that interview question too easily…. The interviewer probably doesn’t understand it either!
Thanks for reading!