Программирование на Objective-C 2.0
Шрифт:
Вывод программы 8.8 x = 200 у = 300
Объект b класса ClassB инициализируется путем вызова метода initVar, определенного в классе ClassB. Этот метод замещает метод initVar из ClassA, присваивает значение 200 переменной х (унаследованное из ClassA) и значение 300 — переменной у (определенной в ClassB). Метод printVar выводит значения этих переменных экземпляра.
Есть много других тонкостей, связанных с выбором метода в ответ на сообщение, особенно в тех случаях, когда получателем является один из нескольких классов. Это динамическое связывание (dynamic binding), которое рассматривается в следующей главе. 8.5. Абстрактные классы
Мы закончим эту главу, добавив еще немного терминологии, связанной с понятием наследования.
Иногда классы создаются просто для того, чтобы упростить другим создание подкласса.
Добавьте в программе 8.1 новый класс с именем ClassC, который является подклассом класса ClassB. Создайте метод initVar, который присваивает значение 300 своей переменной экземпляра х. Напишите тестовую процедуру, которая объявляет объекты классов ClassA, ClassB и ClassC и вызывает их методы initVar.
При работе с объектами высокого разрешения вам может потребоваться координатная система, которая позволяет задавать точки как значения с плавающей точкой вместо целых значений. Внесите изменения в классы XYPoint и Rectangle, чтобы можно было работать с числами с плавающей точкой. Для ширины, высоты, площади и периметра тоже должны использоваться числа с плавающей точкой.
Внесите изменения в программу 8.1, чтобы добавить новый класс с именем ClassB2, который, как и ClassB, является подклассом класса ClassA. Что вы можете сказать о связи между ClassB и ClassB2? Укажите иерархические связи между классом NSObject, классом ClassA, ClassB и ClassB2. Что является суперклассом для ClassB? Что является суперклассом для ClassB2? Сколько подклассов может иметь класс, и сколько он может иметь суперклассов?
Напишите метод Rectangle с именем translate:, который принимает в качестве своего аргумента вектор с именем XYPoint (xv,yv). Сделайте так, чтобы он смещал начало прямоугольника (origin) на указанный вектор.
Определите новый класс с именем GraphicObject и сделайте его подклассом NSObject. Определите переменные экземпляра в этом новом классе следующим образом. int fillColor; // 32-битный цвет BOOL filled; // Заполняется ли объект? int lineColor; // 32-битный цвет линии
Напишите методы, которые задают и считывают значения определенных выше переменных.
Сделайте класс Rectangle подклассом GraphicObject. Определите новые классы Circle (Круг) и Triangle (Треугольник), которые тоже являются подклассами GraphicObject. Напишите методы, чтобы задавать и считывать параметры для этих объектов, вычислять длину окружности и площадь круга, периметр и площадь треугольника.
Напишите метод для 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];