Подклассы и приведение в цель C - PullRequest
4 голосов
/ 12 сентября 2009

Сегодня я столкнулся со странной проблемой. Я создал подкласс UIView и добавил только 1 метод в код шаблона, предоставленный 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 Ответ

11 голосов
/ 12 сентября 2009

На самом деле полиморфизм работает, как и ожидалось. Если бы это не сработало, ничего бы не было напечатано (в вашем примере печатается 0,0000). Дело в том, что, хотя ваш экземпляр фактически отвечает на сообщение testFloat:10.0f, поскольку компилятор не может статически видеть объявление метода (так как класс UIView не объявляет такой метод), он предполагает, что ваш метод принимает ... в качестве аргумента и возвращает id.

Когда CGFloat передается методу, который ожидает переменное число аргументов (...), он переводится в double. Таким образом, получающему методу передается аргумент double, и он считает, что это float, и он не печатается правильно.

Вы можете проверить это поведение, изменив строку NSLog на:

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

Когда компилятор отправляет сообщение FloatView*, а не UIView*, он может найти точную сигнатуру метода. Он может видеть, что действительно ожидает CGFloat и не продвигает аргумент к double. В результате все работает правильно.

Кроме того, если UIView* содержит объявление метода, которое принимает CGFloat, компилятор будет вызывать метод соответствующим образом. Подводя итог, это не проблема полиморфизма; это проблема с отсутствующей подписью метода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...