我想知道语言的面向对象特性是如何在C中实现的。
正如<objc/runtime.h>
中所定义的,id
类型是指向objc_object
的指针,而objc_object
类型是仅包含一个成员{C} {1}}的C结构存储isa
。那么存储任何对象的实例变量的实际值的位置和方式是什么?
另外一件事是,所有Objective-C对象指针都可以转换为Class
(这是一个指向C结构的指针,其中不存在继承等特性)是Objective-C class只是编译器的限定符,所有实例都是id
的同类型的?
加入:
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
谢谢!
答案 0 :(得分:5)
那么存储实例变量的实际值的位置和方式是什么?
它们始终存放在同一个地方 - 在对象内部。如你所说,id
表示指向任何类型对象的指针。但是,除此之外,它没有定义任何特定类型 - 它没有说明对象的实际类型。
objc_object
只是一种基本类型,相当于NSObject
。看一下NSObject.h,您会看到NSObject
的实例有一个实例变量isa
指针。 NSProxy
也是如此,它是Objective-C中的另一个根类。 NSObject
或NSProxy
的子类可以添加自己的实例变量,这些变量将附加到父结构中。
如果所有Objective-C对象指针都可以转换为 id,所有Objective-C类都只是编译器的限定符,并且 在运行时所有这些实例同样类型的objc_object?
我不确定你在这里问的是什么。编译器不会阻止你向任何对象发送任何消息(虽然如果它认为你正在向不支持它的对象发送消息它会发出警告),所以在某种意义上编译器并不关心关于各种对象类型。另一方面,不同类型的对象不同 - 并不是所有类都转换为的通用类型。
id
与void *
强烈相似。 void *
是一个通用指针,您可以将任何指针强制转换为void *
,但这并不意味着所有指针都是等效的。 id
与添加的限制几乎相同,即您为类型id
的变量指定的指针必须指向Objective-C对象。