目标C中的子类化和强制转换

时间:2009-09-12 11:26:28

标签: objective-c polymorphism

我今天遇到了一个奇怪的问题。我创建了一个UIView的子类,并且只为xcode提供的模板代码添加了一个方法。

@interface FloatView : UIView {

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

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

然后在我的appDelegate中,我有这样的代码:

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

非常简单,对吧?这打印出来的是什么?我认为它会像“10.0000”,但不,它打印出“0.000000”。

我在这几个小时里挣扎,试图找出我做错了什么,然后我将appDelegate中的代码更改为

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

只有这样,才打印出预期的“10.0000”。为什么会这样?我已经将FloatView声明为UIView的子类,我不应该将一个FloatView对象分配给UIView指针而不会出现问题吗?

即使floatView被声明为UIView的指针,它实际上是一个floatView,它应该能够处理floatTest消息吗?我完全不在这里吗?

1 个答案:

答案 0 :(得分:11)

实际上,多态性正在按预期工作。如果它不起作用,则不会打印任何内容(在您的示例中,正在打印0.0000)。问题是,虽然你的实例实际上响应了testFloat:10.0f消息,因为编译器不能静态地看到方法声明(因为UIView类没有声明这样的方法),它假定你的方法将...作为参数并返回id

CGFloat传递给需要可变数量的参数(...)的方法时,它会被提升为double。因此,接收方法传递double参数并认为它是float并且它没有正确打印。

您可以通过将NSLog行更改为:

来验证此行为
NSLog(@"%f", *(double*)&x);

当编译器将消息发送到FloatView*而不是UIView*时,它可以找到该方法的确切签名。它可以看到它真的期望CGFloat并且不会将参数提升为double。结果,它正常工作。

此外,如果UIView*包含采用CGFloat的方法声明,编译器将适当地调用该方法。总而言之,这不是多态性问题;这是一个缺少方法签名的问题。