Classes are structs, but Class
is a pointer type, being defined as
typedef struct objc_class *Class;
and this answers the first part of the question.
Now, if you take a look at <objc/objc.h>
you'll find
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;
struct objc_cache *cache OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
and in <obj/runtime.h>
you'll find
/// Represents an instance of a class.
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
meaning that in Objective-C 2.0 objc_object
and objc_class
are identical structs, both having an isa
field.
That's why you can pass a Class
where an id
is required: classes are objects after all.
You would normally expect a warning about the incompatible pointers type, but apparently the Obj-C compiler uses an ad-hoc treatment this specific case.
I have no references to support this, though.
EDIT
I finally found a reference in the clang source code:
In ASTContext.cpp
, this is the Class
declaration
TypedefDecl *ASTContext::getObjCClassDecl() const {
if (!ObjCClassDecl) {
QualType T = getObjCObjectType(ObjCBuiltinClassTy, 0, 0);
T = getObjCObjectPointerType(T);
TypeSourceInfo *ClassInfo = getTrivialTypeSourceInfo(T);
ObjCClassDecl = TypedefDecl::Create(const_cast<ASTContext &>(*this),
getTranslationUnitDecl(),
SourceLocation(), SourceLocation(),
&Idents.get("Class"), ClassInfo);
}
return ObjCClassDecl;
}
and this is the id
declaration
TypedefDecl *ASTContext::getObjCIdDecl() const {
if (!ObjCIdDecl) {
QualType T = getObjCObjectType(ObjCBuiltinIdTy, 0, 0);
T = getObjCObjectPointerType(T);
TypeSourceInfo *IdInfo = getTrivialTypeSourceInfo(T);
ObjCIdDecl = TypedefDecl::Create(const_cast<ASTContext &>(*this),
getTranslationUnitDecl(),
SourceLocation(), SourceLocation(),
&Idents.get("id"), IdInfo);
}
return ObjCIdDecl;
}
In both cases the type is set to the result of getObjCObjectPointerType
. This causes the compiler to consider both Class
and id
as pointers to Objective-C objects.