陷于理解Objective-c中的动态绑定

陷于理解Objective-c中的动态绑定,objective-c,dynamic-binding,Objective C,Dynamic Binding,我刚刚开始学习Objective-C,我正在阅读Stephen G.Kochan的《Objective-C第三版编程》 有一段解释了多态机制: 在运行时,Objective-C运行时系统将检查dataValue1(id对象)中存储的对象的实际类,并从正确的类中选择要执行的适当方法。但是,在更一般的情况下,编译器可能会生成错误的代码,将参数传递给方法或处理其返回值。例如,如果一个方法以对象为参数,而另一个方法以浮点值为参数,则会发生这种情况。或 例如,如果一个方法返回一个对象,另一个方法返回一个整

我刚刚开始学习Objective-C,我正在阅读Stephen G.Kochan的《Objective-C第三版编程》

有一段解释了多态机制:

在运行时,Objective-C运行时系统将检查dataValue1(id对象)中存储的对象的实际类,并从正确的类中选择要执行的适当方法。但是,在更一般的情况下,编译器可能会生成错误的代码,将参数传递给方法或处理其返回值。例如,如果一个方法以对象为参数,而另一个方法以浮点值为参数,则会发生这种情况。或 例如,如果一个方法返回一个对象,另一个方法返回一个整数。如果两个方法之间的不一致只是不同类型的对象(例如,分数的add:方法将分数对象作为其参数并返回一个,而复数的add:方法将获取并返回一个复杂对象),编译器仍将生成正确的代码,因为内存地址(即指针)仍然作为对象的引用传递

我不太明白,这一段的第一部分说,如果我用相同的名称和不同类型的参数在不同的类中声明两个方法,编译器可能会生成错误的代码。虽然这一段的最后一部分说,有两个具有相同名称、不同参数和返回类型的方法是可以的……哦,不

我有以下代码,它们可以正常编译和运行:

@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]);
编辑: 正如我所引用的文本,上面的代码应该会导致错误,但它只会产生一些警告消息,名为“add:”的多个方法找到了指向整数转换的不兼容指针将“id”发送到“int”类型的参数

我有java和C++背景,我知道Objtovi-C中的多态性和那些语言有点不同,但我仍然对不确定性(粗体文本)感到困惑。

我想我一定是误解了什么,你能为我和需要它的人更详细地解释一下Objective-C中的动态绑定吗


谢谢你

之所以区别是因为在后一种情况下,区别仅在参数类中
Complex*
Fraction*
都是指针,所以即使这两个同名方法之间存在混淆,也没有问题

另一方面,您在示例中遇到的情况是危险的,因为一个参数是指针,另一个是
int
。但是,要做到这一点很容易:

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

您没有注意到任何异常,因为这两个方法在x86_64 ABI下具有相同的调用语义。指针可以被视为整数,在x86_64 ABI下,它们以相同的方式传递给目标方法

但是,如果您有其他课程,例如:

@implementation C
- (int)add:(float)number {
    return (int)number + 100;
}
@end
接收浮点参数(如Kochan所述),然后编译器在解析时:

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]);
不知道对于
[c add:100]
它应该将
100
放在x86_64 ABI指定的浮点寄存器中。因此,
-[C add:][/code>期望浮点参数位于浮点寄存器中,它读取的值与
100
参数不对应

要使其工作,您必须使用静态类型声明变量:

C *c = [[C alloc] init];
或在发送消息时将其强制转换为正确的类型:

[(C *)c add:100];

在一天结束时,发送Objective-C消息是一个函数调用。不同的ABI可能具有不同的语义,用于调用具有变量参数、浮点与整数参数或返回值、或结构(而不是标量算术类型)的函数。如果编译器看到不同的方法签名根据目标ABI进行了不同的处理,并且如果没有足够的可用类型信息,则可能最终选择错误的方法签名。

相关:。感谢您的输入。我的困惑现在消除了。但这也让我觉得Objective-C中的动态绑定并不是那么安全。只需确保在发送类型不明确的消息之前显式地强制转换任何变量即可。请注意,由于Cocoa的命名约定,大多数参数都是经过描述的(
stringByAppendingString:
numberWithFloat:
),因此很少有同名但类型不同的方法。@Neevek除了andyvnn22所说的以外,如果您使用相同的名称(选择器)声明方法,编译器将向您发出警告还有不同的签名。