Чтение онлайн

ЖАНРЫ

Программирование на Objective-C 2.0
Шрифт:

Вывод программы 8.8 x = 200 у = 300

Объект b класса ClassB инициализируется путем вызова метода initVar, определенного в классе ClassB. Этот метод замещает метод initVar из ClassA, присваивает значение 200 переменной х (унаследованное из ClassA) и значение 300 — переменной у (определенной в ClassB). Метод printVar выводит значения этих переменных экземпляра.

Есть много других тонкостей, связанных с выбором метода в ответ на сообщение, особенно в тех случаях, когда получателем является один из нескольких классов. Это динамическое связывание (dynamic binding), которое рассматривается в следующей главе. 8.5. Абстрактные классы

Мы закончим эту главу, добавив еще немного терминологии, связанной с понятием наследования.

Иногда классы создаются просто для того, чтобы упростить другим создание подкласса.

Такие классы называют абстрактными (abstract) или абстрактными суперклассами. В этом классе определяются методы и переменные экземпляра, но при этом не предполагается, что кто-либо будет создавать экземпляры из этого класса. Например, р нет никакого смысла определить объект непосредственно из корневого объекта NSObject. Foundation framework (см. часть II) содержит несколько абстрактных классов. Например, класс Foundation NSNumber является абстрактным классом, который был создан для работы с числами как с объектами. Для хранения целых чисел и чисел с плавающей точкой обычно требуются разные размеры памяти. Для каждого числового типа существуют отдельные подклассы NSNumber. Поскольку эти подклассы, в отличие от их абстрактных суперклассов, реально существуют, их называют конкретными (concrete) подклассами. Каждый конкретный подкласс является дочерним классом класса NSNumber и называется кластером (cluster). Когда вы отправляете сообщение классу NSNumber для создания нового объекта типа integer, используется соответствующий подкласс, чтобы выделить память для этого объекта и задать его значение. Эти подклассы на самом деле являются частными. Вы не можете выполнить непосредственный доступ к этим подклассам сами; доступ осуществляется косвенно через абстрактный суперкласс. Абстрактный суперкласс представляет общий интерфейс для работы со всеми типами числовых объектов и позволяет вам не знать, какой тип числа вы сохранили в вашем числовом объекте и как задавать и считывать его значение. Упражнения

Добавьте в программе 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];

Поделиться с друзьями: