我想知道该语言的面向对象特性是如何在 C 中实现的。
如 中所定义<objc/runtime.h>
,id
type 是一个指向 a 的指针objc_object
,objc_object
type 是一个只有一个成员isa
存储 a的 C 结构Class
。那么任何对象的实例变量的实际值存储在哪里以及如何存储?
还有一件事,所有 Objective-C 对象指针都可以转换为id
(这是一个指向 C 结构的指针,其中不存在继承等特性),Objective-C 类只是编译器的限定符,并且所有实例的类型相同objc_object
?
添加:
NSObject *obj = [NSObject new];
objc_object *objStruct = (__bridge objc_object *)obj;
NSLog(@"obj: %@", NSStringFromClass(objStruct->isa));
NSString *str = [NSString new];
objc_object *strStruct = (__bridge objc_object *)str;
NSLog(@"str: %@", NSStringFromClass(strStruct->isa));
此代码编译并输出:
obj: NSObject, str: __NSCFConstantString
两者obj
和str
都可以转换为objc_object *
,这意味着两个变量都是相同类型的指针,不是吗?
解决
明白了!我误解了指针转换的工作原理。obj
和str
是不同结构类型的指针,但两者通常isa
在内存前面都有类类型成员,因此可以视为objc_object
. 下面的代码模仿了这种机制:
typedef struct {
int isa;
} Fake_NSObject;
typedef struct {
int isa;
char *string;
} Fake_NSString;
Fake_NSObject obj = {1};
Fake_NSObject *objPtr = &obj;
NSLog(@"obj: %d", objPtr->isa); // prints 1
Fake_NSString str = {2, "abc"};
Fake_NSString *strPtr = &str;
NSLog(@"str: %d", strPtr->isa); // prints 2
Fake_NSObject *objPtr2 = (Fake_NSObject *)strPtr; // this is ok.
NSLog(@"obj2: %d", objPtr2->isa); // prints 2
Fake_NSString *strPtr2 = (Fake_NSString *)objPtr; // this is invalid, but still works.
NSLog(@"str2: %d", strPtr2->isa); // prints 1
谢谢!