2009-09-12 41 views
4

今天我遇到了一個奇怪的問題。我創建了UIView的一個子類,並且僅向xcode提供的模板代碼添加了1個方法。目標C中的子類化和鑄造

@interface FloatView : UIView { 

} 
- (void)floatTest:(CGFloat)x; 
@end 

- (void)floatTest:(CGFloat)x { 
    NSLog(@"float was %f", x); 
} 

然後在我的appDelegate我有這樣的代碼:

​​

很簡單,不是嗎?該打印什麼?我認爲它會像「10.0000」,但不是,它打印出「0.000000」。

我糾結這個了幾個小時,試圖找出我在做什麼錯了,然後我改變了代碼在我的appDelegate到

FloatView *floatView = [[FloatView alloc] init]; 
[floatView floatTest:10.0f]; 

只有到那時,沒有它打印出預期的「10.0000」 。這是爲什麼?我已經宣佈FloatView作爲UIView的子類,我不應該能夠將一個FloatView對象分配給沒有問題的UIView指針?

儘管floatView被聲明爲UIView的指針,但它確實是一個floatView,它應該能夠處理floatTest消息?我完全脫離基地嗎?

+0

你的代碼生成了一個編譯器警告,對吧?如果你已經明白了原因,你就可以解決問題。 – bbum 2009-09-12 18:36:04

+0

它可能已經解決了這個問題,但我可能不會理解它爲什麼會如此行事。您的評論真的沒有幫助。感謝Mehrdad Afshari的詳細迴應。 – 2011-12-14 13:28:01

回答

11

實際上,多態性按預期工作。如果不起作用,則不會打印任何內容(在您的示例中,正在打印0.0000)。事實上,雖然你的實例實際上響應了testFloat:10.0f消息,但由於編譯器不能靜態地看到方法聲明(因爲UIView類沒有聲明這種方法),它假定你的方法以...作爲參數並返回id

當將CGFloat傳遞給需要可變數量參數的方法(...)時,它被提升爲double。因此,接收方法通過了一個double參數,並認爲它是一個float並且它沒有正確打印。

你可以通過改變NSLog線來驗證此行爲:

NSLog(@"%f", *(double*)&x); 

當編譯器將消息發送給FloatView*而非UIView*,它可以找到方法的準確簽名。它可以看到它真的期望CGFloat,並且不會將參數提升爲double。因此,它正常工作。

此外,如果UIView*包含採用CGFloat的方法聲明,則編譯器會適當地調用該方法。總而言之,這不是一個多態問題;這是一個缺少方法簽名問題。