2011-10-07 58 views
3

我有2類A和B,B是從A繼承,A是從NSObject.Class甲繼承具有如下功能: - (無效)INIT:目標C init方法和繼承

- (void)init { 
if (self = [super init]) { 

NSLog(@"A");  

} 
return self; 
} 

B具有:

- (id)init { 
if (self = [super init]) { 

NSLog(@"B");  

} 
return self; 
} 

編譯後,我在我的控制檯「A」和「B」的,儘管在B「如果(自= [超級初始化])」不可能是真實的情況,導致其超類的init方法返回void.Any想法?

P.S.我知道init方法必須返回id,我感興趣的是爲什麼這個工作,而不應該。

回答

5

聽Chuck。他很聰明:)

我會嘗試添加更多的細節。想想這個

的方法之一是「如果兩人都宣佈-(id)init如何將一個返回其值設置爲B」?

它是這樣的。 return self聲明將把指針指向A,並將其放在約定的位置。該位置將在ABI中定義。在OSX/x86-64機器上,它是RAX寄存器(IIRC)。所以return self真的說「把自己的指針寫入RAX」。

然後當B重新獲得控制,它知道返回值是RAX,並且可以使用它是什麼樣子。請注意,您並未從A的實施中刪除return self聲明,因此自我可能仍然寫入RA中,B發現並使用它。或者也許RAX仍然有NSObject init實現的指針。你必須反彙編才能確定。

現在,讓我們說你沒有保持return self在A的實施。現在,RA中有一些隨機垃圾,B將嘗試使用它,像是指向A的指針。這是Chuck提到的未定義行爲的來源。如果幸運的話,它只會崩潰。

我猜你的代碼上面給出了一些編譯器錯誤/警告,你必須壓制?

+0

是,警告「迴歸與空函數」 –

+3

IIRC,一些編譯器會扔掉返回值的void函數,即使你明確地寫出來。它看來,蘋果的不對,但它沒有什麼依賴。這真的是*未定義的行爲發揮作用。 – Chuck

5

您正在通過分配void函數調用的結果來調用未定義的行爲。未定義的行爲意味着幾乎可以發生任何事情。這屬於「任何東西」的標題,所以它可能發生。至於爲什麼編譯器沒有注意到你的錯誤:你可能忽略了在你的頭文件中聲明重寫,所以它假定你的方法和它可以找到的最近的聲明NSObject一樣具有相同的簽名。