2013-05-28 53 views
4

我想知道該語言的面向對象的特徵是如何在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 

兩個objstr可澆鑄objc_object *,這意味着這兩個變量是相同的類型,指針不?

解決

明白!我誤解了指針投射的工作原理。 objstr是不同結構類型的指針,但通常在內存的前端都具有類型成員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 

謝謝!

回答

5

然後在哪裏以及如何存儲實例變量的實際值?

它們存儲在與對象相同的位置。正如你所說,id代表一個指向任何類型的對象。然而,它沒有定義任何特定的類型 - 它沒有說任何關於對象類型的實際。

objc_object只是一個基本類型,相當於NSObject。看看NSObject.h,你會發現NSObject的實例只有一個實例變量,即isa指針。 NSProxy也是如此,這是Objective-C中的另一個根類。 NSObjectNSProxy的子類可以添加自己的實例變量,這些實例變量會附加到父級結構中。

如果所有的Objective-C對象指針可以強制轉換爲 ID,都是Objective-C類只是編譯器預選賽,並 在運行時所有這些情況下同樣objc_object的類型?

我不確定你在問什麼。編譯器不會阻止你發送任何消息給任何對象(儘管它會警告你是否認爲你發送消息給一個不支持它的對象),所以從某種意義上說,編譯器並不關心關於各種對象類型。另一方面,不同類型的對象不同 - 不存在所有類都轉換爲的通用類型。

id非常類似於void *void *是一個通用指針,您可以將任何指針強制轉換爲void *,但這並不意味着所有指針都是等價的。 id與添加的限制幾乎相同,您分配給類型爲id的變量的指針必須指向Objective-C對象。

+0

'id'明顯不同於'void *',因爲它實際上被定義爲指向C結構的指針,並且如果任何變量能夠轉換爲該類型,那意味着變量必須是它的類型呢,不是? –

+0

@TaketoSano對象只是存在感的結構。 「對象內部」意味着ivars是(字面上)對象本身結構的一部分。你甚至可以通過從'objc_object'派生它並將'isa'設置爲一個有效的類來使一個C++類成爲一個ObjC對象。在語言環境中,'id'的意思是「我可以回覆任何消息」,而不是「我可以填寫任何類型」。 (這只是它的實現的一個副作用) – CodaFi

+0

那麼它們如何被轉換成一個「基本」結構,其成員和大小較少? –

相關問題