Шрифт:
Напишите метод для Rectangle с именем intersect:, который принимает прямоугольник как аргумент и возвращает прямоугольник, представляющий площадь перекрытия этих прямоугольников. Например, для двух прямоугольников, показанных на рис. 8.Ю, метод должен возвращать прямоугольник, начало (origin) которого находится в точке (400, 420), ширина (width) равна 50 и высота (height) равна 60.
Рис. 8.10. Пересечение прямоугольников
Если прямоугольники не пересекаются, нужно возвратить прямоугольник с шириной и высотой 0 и началом (0,0).
Напишите метод для класса Rectangle с именем draw, который рисует прямоугольник из знаков «минус» и «вертикальная черта». Следующая последовательность кодов Rectangle *myRect = [[Rectangle alloc] init]; [myRect setWidth: 10 and Height: 3]; [myRect draw]; [myRect release]; _______ | | | | | | _______
Глава 9. Полиморфизм, динамический контроль типов и динамическое связывание
В этой главе описываются возможности языка Objective-C, которые делают его столь мощным языком программирования и отличают его от некоторых объектно-ориентированных языков, таких как C++. Это три ключевых концепции: полиморфизм, динамический контроль типов и динамическое связывание.
Полиморфизм (polymorphism) позволяет разрабатывать программы таким образом, чтобы объекты из различных классов могли определять методы, которые имеют одно и то же имя. Динамический контроль типов (dynamic typing) позволяет откладывать определение класса, которому принадлежит объект, до выполнения программы. Динамическое связывание (dynamic binding) позволяет откладывать определение конкретного метода для вызова в объекте до начала выполнения программы. 9.1. Полиморфизм: одно имя, различные классы
В программе 9.1 показан файл секции interface для класса Complex, который используется для представления в программе комплексных чисел. Программа 9.1. Файл секции interface Complex.h // файл секции interface для класса Complex #import <Foundation/Foundation.h> @interface Complex: NSObject { double real; double imaginary; } @property double real, imaginary; -(void) print; -(void) setReal: (double) a andlmaginary: (double) b; -(Complex *) add: (Complex *) f; @end
В упражнении 6 главы 4 мы создали секцию implementation для этого класса. Мы добавили дополнительный метод setReal:andlmaginary:, чтобы задавать вещественную и мнимую части числа с помощью одного сообщения, а также синтезировали методы доступа. Это показано в следующей программе. Программа 9.1. Файл секции implementation Complex.m // Файл секции implementation для класса Complex #import "Complex.h" @implementation Complex @synthesize real, imaginary; -(void) print { NSLog (@" %g + %gi", real, imaginary); } -(void) setReal: (double) a andlmaginary: (double) b { real = a; imaginary = b; } -(Complex *) add: (Complex *) f { Complex *result = [[Complex alloc] init]; [result setReal: real + [f real] andlmaginary: imaginary + [f imaginary]]; return result; } @end
Программа 9.1. Тестовая программа main.m // Совместно используемые имена методов: полиморфизм #import "Fraction.h #import "Complex.h" int main (int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; Fraction *f1 = [[Fraction alloc] init]; Fraction *f2 = [[Fraction alloc] init]; Fraction *fracResult; Complex *c1 = [[Complex alloc] init]; Complex *c2 = [[Complex alloc] init]; Complex *compResult; [f1 setTo: 1 over: 10]; [f2 setTo: 2 over: 15]; [c1 setReal: 18.0 andlmaginary: 2.5]; [c2 setReal: -5.0 andlmaginary: 3.2]; // добавление и вывод 2 комплексных чисел [d print]; NSLog (@" +"); [с2 print]; NSLog (@и............ "); compResult = [d add: с2]; [compResult print]; NSLog (@"\n"J; [c1 release]; [c2 release]; [compResult release]; // добавление и вывод 2 дробей [f1 print]; NSLog (@" +"); [f2 print]; NSLog (<§>"-—"); fracResult = [f1 add: f2]; [fracResult print]; [f1 release]; [f2 release]; [fracResult release]; [pool drain]; return 0; }
Вывод программы 9.1 18 + 2.5i + -5 + 3.2i 13 + 5.7i 1/10 + 2/15 7/30
Отметим, что оба класса, Fraction и Complex, содержат методы add: и print. Но откуда система знает, какие методы нужно вызывать при выполнении следующих выражений с сообщениями? compResult = [d add: с2]; [compResult print];
Системе выполнения (runtime) Objective-C известно, что с1, получатель первого сообщения, является объектом класса Complex. Поэтому выбирается метод add:, определенный для класса Complex. Система выполнения Objective-C определяет также, что compResult является объектом класса Complex, поэтому она выбирает метод print, определенный в классе Complex, чтобы вывести результат сложения. То же самое относится к следующим выражениям с сообщениями. fracResult = [f1 add: f2]; [fracResult print];
Примечание. Система всегда содержит информацию о классе, которому принадлежит объект. Это позволяет ей принимать нужные решения во время выполнения, не во время компиляции. Подробнее об этом рассказывается в главе 13. Выбор методов из класса Fraction выполняется при оценке выражения с сообщением в зависимости от класса П и fracResult.
Возможность использования одного имени из различных классов называется полиморфизмом. Полиморфизм позволяет вам разрабатывать набор классов с одинаковым именем метода. В определение каждого класса включается код, необходимый для ответа на вызов данного определенного метода, и это делает его независимым от определений в других классах. Это позволяет также добавлять новые классы, которые могут отвечать на вызов методов с тем же именем.
Примечание. Именно классы Fraction и Complex (а не тестовая программа) должны предусматривать освобождение памяти, занимаемой результатами их методов add:. На самом деле эти объекты должны освобождаться автоматически (autorelease). Подробнее об этом рассказывается в главе 18. 9.2. Динамическое связывание и тип id
В главе 4 уже говорилось, что тип данных id является обобщенным типом объекта. Это означает, что id используется для хранения объектов, которые принадлежат любому классу. Он используется для хранения в переменной различных типов объектов. Рассмотрим программу 9.2 и ее вывод. // Пример динамического контроля типов и динамического связывания #import Traction.h" #import "Complex.h" int main (int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; id dataValue; Fraction *f1 = [[Fraction alloc] init]; Complex *c1 = [[Complex alloc] init]; [f1 setTo: 2 over: 5]; [c1 setReal: 10.0 andlmaginary: 2.5]; // в первый раз dataValue присваивается дробь (fraction) dataValue = f1; [dataValue print]; // теперь dataValue присваивается комплексное число (complex) dataValue = c1; [dataValue print]; [c1 release]; [f1 release]; [pool drain]; return 0; }