Re: OOP Clarification: difference between classes and instances, compare with C++
Re: OOP Clarification: difference between classes and instances, compare with C++
- Subject: Re: OOP Clarification: difference between classes and instances, compare with C++
- From: Thomas Lachand-Robert <email@hidden>
- Date: Tue, 1 Jan 2002 13:25:33 +0100
Le lundi 31 dicembre 2001, ` 11:48 , Stephen A. Cochran a icrit :
I've read about the difference between a class method and a instance
method
before, but the difference has somehow become lost in my cobwebs. All I
can
remember is the difference is subtle, but an important concept.
It is important, but there is nothing subtle or mysterious in the
difference. Since it is a frequently asked question, I will try a detailed
answer, and do a comparison with C++ that many people already know there.
Suppose you define a class like that:
@interface MyClass : NSObject {
int member1, member2;
float otherMember;
}
+(void)doSomething;
-(id)init;
-(void)aMethod;
@end
and then use it somewhere like that:
MyClass *a = [[MyClass alloc] init];
[a aMethod];
Then your program creates an object 'a' which is basically a struct
containing
{
/* here some additional intendance members */
int member1, member2;
float otherMember;
}
(It turns out that the intendance members is a pointer named _isa; but you
don't have to care usually.)
Such an object is called an 'instance' of the class MyClass, and you can
create as many as you need.
As soon as you begin to use the class, here for the first [MyClass alloc],
the program automatically creates an additional object named MyClass: that
is the class object. There is only one of them for each class defined, and
it doesn't contain any member (except isa, again). You can send it any
message (like always in Obj-C), but it responds only to the messages
defined with a '+' in front (like 'doSomething' in my example), not to
those with a '-' (these ones are for the instances of the class, like
'init', 'aMethod'). Hence you can do
[MyClass doSomething];
[a aMethod];
but not
[MyClass aMethod]; // NO! MyClass is not an instance of 'MyClass'
[a doSomething]; // NO! doSomething is a class method
Note that inside each method, you can use 'self': it refers to the object
for which the method was called, hence the class in 'doSomething', the
instance in 'aMethod'. For every instance object, [self class] gives the
corresponding class object.
Important: any class object gets automatically a few methods. The most
important is 'alloc': it tells the class object to create a new instance.
Hence a = [[MyClass alloc] init] does the following:
1/ creates the clas object if it doesn't exist already;
2/ send the message 'alloc' to the class object: this must return an
object (an instance of the class, usually, but not always: it could be an
instance of a hidden subclass);
3/ send the 'init' message to the new created object, and copies the
returned value in 'a'.
It is important to always chain these calls like that, since it allows the
'init' method to modify the object and return a different one, if needed.
So DON'T write
a = [MyClass alloc]; [a init]; // NO!
(My feeling is that is the nested [[MyClass alloc] init] who confuses
people about classes and instances... but it is important to do this
chaining.)
Another important class method is 'initialize' (more precisely
+(void)initialize). It is called when the class object is created, hence
it is the 'init' method of the class object. It defaults to doing nothing,
but you can override it to create global variables for example.
If your class contains a global variable (a dictionar, say), you can add a
class method
+(NSDictionary*)classDictionary;
that returns it, and init the dictionary in this method, or in 'initialize'
. In the latter case, the dictionary pointer must be kept as a global
static variable in you implementation file; in the former case, it is
enough to have it as a static variable in the 'classDictionary' method.
COMPARAISON WITH C++:
In C++ there is no class objects, only instances. You can create class
methods by using static methods, and class variables using static
variables. So it is roughtly equivalent, except on two subtle points:
1/ there is no C++ equivalent to 'initialize', so to init a class in C++
you must use a contorted way;
2/ there is no class object, which means you cannot get the class. Hence
there is no C++ equivalent to the following:
void printClassOf(id object) {
printf("The class of %@ is %@.", object, [object class]);
}
This is important in some critical points, like the copy method. Assume
that MyClass implements copy, but its superclass doesn't (this is true for
any class whose superclass is NSObject in particular).
Can you see the difference between
-(id)copy {
return [[MyClass alloc] initWithValue:[self value]]; // incorrect!
}
and
-(id)copy {
return [[[self class] alloc] initWithValue:[self value]]; // correct
}
(except the fact that it is the incorrect way which is documented by Apple
;-)?
Here it is: the subclasses of any class containing already a copy method
should implemented copy like that:
-(id)copy {
id theCopy = [super copy]; // ensure that the members of the
superclass are copied
/* here copy the members of the derived class */
return theCopy;
}
Now you see why the first 'copy' method is incorrect: the allocated object
doesn't belong to the derived class, hence there is no room for new
members.
The correct copy method doesn't need to be modified in any derived class
that has no additional members, or whose additional members should init to
0. Creating an equivalent of this copy method in C++ is very difficult
(hence the need of copy constructors in every class).
Thomas Lachand-Robert
********************** email@hidden
<< Et le chemin est long du projet ` la chose. >> Molihre, Tartuffe.