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

发布于 2024-12-13 19:15:28 字数 1242 浏览 1 评论 0原文

我刚刚开始学习 Objective-C,正在阅读 Stephen G. KochanProgramming in Objective-C 3rd Edition

有一段解释了多态机制:

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

我不太明白该段落的第一部分说,如果我在不同的类中声明具有相同名称和不同类型参数的 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]);

编辑: 正如我引用的文本,上面的代码应该会导致错误,但它只产生一些警告消息,发现多个名为“add:”的方法发送“id”的整数转换不兼容的指针”到“int”类型的参数

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

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

感谢您!

I have just started learning Objective-C, I am reading Programming in Objective-C 3rd Edition by Stephen G. Kochan.

There's a paragraph explaining the polymorphism mechanism:

At runtime, the Objective-C runtime system will check the actual class of the object stored inside dataValue1(an id object) and select the appropriate method from the correct class to execute. However, in a more general case, the compiler might generate the incorrect code to pass arguments to a method or handle its return value.This would happen if one method took an object as its argument and the other took a floating-point value, for example. Or
if one method returned an object and the other returned an integer, for example. If the inconsistency between two methods is just a different type of object (for example, the Fraction’s add: method takes a Fraction object as its argument and returns one, and the Complex’s add: method takes and returns a Complex object), the compiler will still generate the correct code because memory addresses (that is, pointers) are passed as references to objects anyway.

I don't quite get it that the first part of the paragraph says that the compiler might generate incorrect code if I declare 2 methods in different classes with the same name and different type of arguments. while the last part of the paragraph says that it is fine to have 2 methods with the same name and different arguments and return types...oh no...

I have the following code and they compile and run fine:

@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]);

Edit:
As the text I cited, the code above is supposed to cause errors, but it only produces some warning messages, Multiple methods named "add:" found, Incompatible pointer to integer conversion sending "id" to parameter of type "int"

I have Java and C++ background, I know polymorphism in Objective-C is slightly different from that of those languages but I am still confused about the uncertainty(text in bold).

I think I must have misunderstood something, would you please explain in more detail about dynamic binding in Objective-C for me and those who need it?

Thanks you!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

洛阳烟雨空心柳 2024-12-20 19:15:28

您没有注意到任何异常,因为这两个方法在 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:](期望浮点参数位于浮点寄存器中)读取的值与 100 不对应争论。

为了让它工作,你必须用静态类型声明变量:

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

或者在发送消息时将其转换为正确的类型:

[(C *)c add:100];

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

You haven’t noticed anything unusual because those two methods have the same call semantics under, for example, the x86_64 ABI. Pointers can be considered integers and, under the x86_64 ABI, they are passed to the target method in the same manner.

However, if you had another class, e.g.:

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

receiving a floating-point argument (as mentioned by Kochan), then the compiler, when parsing:

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]);

wouldn’t know that for [c add:100] it should place 100 in a floating-point register as specified by the x86_64 ABI. Consequently, -[C add:], which expects the floating-point argument to be in a floating-point register, reads a value that doesn’t correspond to the 100 argument.

For it to work, you would have to either declare the variable with a static type:

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

or cast it to the correct type when sending a message:

[(C *)c add:100];

At the end of the day, sending an Objective-C message is a function call. Different ABIs may have different semantics for calling functions with variable arguments, floating-point vs. integer arguments or return values, or structures instead of scalar arithmetic types. If the compiler sees different method signatures that are handled differently according to the target ABI, and if there is not enough type information available, it may end up choosing the wrong method signature.

骄兵必败 2024-12-20 19:15:28

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

另一方面,您在示例中遇到的情况是危险的,因为一个参数是指针,另一个参数是 int。然而,确保这一点的安全很容易:

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

The distinction is made because in the latter case, the difference is only in the class of the arguments. Complex* and Fraction* are both pointers, so even if there's confusion between the two identically-named methods, there's no issue.

The situation you have in your example, on the other hand, is dangerous, because one argument is a pointer and the other is an int. Being safe about this is easy, however:

NSLog(@"A: %i, B %i", [(A*)a add:100], [(B*)b add:b]);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文