2011-11-06 42 views
3

我剛開始學習Objective-C,我被斯蒂芬·G·庫奇閱讀Objective-C的第三版編程。滯留在理解Objective-C的動態綁定

有一個段落說明多態性機構:

在運行時,Objective-C運行系統將檢查實際的類對象的存儲內dataValue1(一個id對象)並選擇適當的方法從正確的類到執行。然而,在更一般的情況下,編譯器可能產生不正確的代碼將參數傳遞給方法或處理,如果一個方法把一個對象作爲參數,另一個花了浮點其回報價值。會發生例如,點值。例如,如果一個方法返回一個對象,而另一個返回一個整數,則返回 。如果兩個方法之間的不一致只是一種不同類型的對象(例如,Fraction的add:方法將Fraction對象作爲其參數並返回一個,而Complex的add:方法接受並返回一個Complex對象),編譯器將仍然會生成正確的代碼,因爲無論如何都將內存地址(即指針)作爲對象的引用進行傳遞。

我不太明白,該段的第一部分說,編譯器可能產生不正確的代碼,如果我宣佈2種方法在不同的類具有相同的名稱和不同類型的參數。而該段的最後一部分說,這是罰款,有2種方法具有相同的名稱和不同的參數和返回值的類型......哦不......

我有以下的代碼,他們編譯和運行良好:

@implementation A 
- (int) add:(int)a { 
    return 1 + a; 
} 
@end 
@implementation B 
- (int) add: (B*) b { 
    return 100; 
} 
@end 
id a = [[A alloc] init]; 
id b = [[B alloc] init]; 
NSLog(@"A: %i, B %i", [a add:100], [b add:b]); 

編輯: 正如我所引用的文字,上面的代碼應該引起錯誤,但它只是產生一些警告消息,名爲「補充:」 多種方法找到不兼容的指針整數轉換髮送 「ID」 到類型的參數 「INT」

我有Java和C++背景,我知道Objective-C中的多態性與那些語言稍有不同,但我仍然對不確定性(粗體文本)感到困惑。

我想我一定是誤解了什麼東西,你會請有關動態Objective-C中,我結合和那些誰需要更詳細的解釋?

謝謝你!

+0

相關:[非正式協議的需求是什麼?](http://stackoverflow.com/q/7561630/557219)。 – 2011-11-06 05:24:33

回答

6

你有沒有注意到有什麼異常,因爲這兩種方法具有相同的調用語義下,例如,x86_64的ABI。指針可以被認爲是整數,在x86_64 ABI下,它們以相同的方式傳遞給目標方法。

然而,如果有另一個類,例如:

@implementation C 
- (int)add:(float)number { 
    return (int)number + 100; 
} 
@end 

接收浮點參數(如由科昌提到的),則編譯器,解析時:

id a = [[A alloc] init]; 
id b = [[B alloc] init]; 
id c = [[C alloc] init]; 
NSLog(@"A: %i, B %i, C %i", [a add:100], [b add:b], [c add:100]); 

止跌」 t知道[c add:100]它應該將100放在x86_64 ABI指定的浮點寄存器中。因此,期望浮點參數在浮點寄存器中的-[C add:]將讀取與參數100不對應的值。

對於它的工作,你就必須要麼靜態類型聲明變量:

C *c = [[C alloc] init]; 

或發送郵件時將它轉換爲正確的類型:

[(C *)c add:100]; 

在當天結束時,發送一個Objective-C消息是一個函數調用。不同的ABI可能具有不同的語義,用於調用具有可變參數的函數,浮點與整數參數或返回值,或結構而不是標量算術類型。如果編譯器看到根據目標ABI不同處理的不同方法簽名,並且如果沒有足夠的類型信息可用,它最終可能會選擇錯誤的方法簽名。

+0

感謝您的意見。我的困惑現在已被清除。但它也讓我覺得Objective-C中的動態綁定並不安全。 – neevek

+1

只要確保在發送含有不明確類型的消息之前顯式轉換任何變量。請注意,由於Cocoa的命名約定,大多數參數都被描述('stringByAppendingString:','numberWithFloat:'),所以很少有同名但不同類型的方法。 – andyvn22

+0

@Neevek除了andyvnn22說的,編譯器會警告你,如果你聲明具有相同名稱(選擇器)和不同簽名的方法。 – 2011-11-06 20:33:55

3

的區別在於,因爲在後者的情況下製成,不同的是僅在類的參數。 Complex*Fraction*都是指針,所以即使兩個同名命名方法混淆,也沒有問題。

另一方面,您在示例中的情況很危險,因爲一個參數是指針,另一個參數是int。作爲這個安全是容易的,但是:

NSLog(@"A: %i, B %i", [(A*)a add:100], [(B*)b add:b]);