我想知道該語言的面向對象的特徵是如何在C.Objective-c對象是所有相同類型的C結構嗎?
實現爲<objc/runtime.h>
定義,id
類型是一個指向objc_object
,和objc_object
類型是C-結構僅具有一個成員isa
存儲一個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
謝謝!
'id'明顯不同於'void *',因爲它實際上被定義爲指向C結構的指針,並且如果任何變量能夠轉換爲該類型,那意味着變量必須是它的類型呢,不是? –
@TaketoSano對象只是存在感的結構。 「對象內部」意味着ivars是(字面上)對象本身結構的一部分。你甚至可以通過從'objc_object'派生它並將'isa'設置爲一個有效的類來使一個C++類成爲一個ObjC對象。在語言環境中,'id'的意思是「我可以回覆任何消息」,而不是「我可以填寫任何類型」。 (這只是它的實現的一個副作用) – CodaFi
那麼它們如何被轉換成一個「基本」結構,其成員和大小較少? –