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

на главную - закладки

Жанры

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

Полиморфизм (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; }

Вывод программы 9.2 2/5 10 + 2.5i

Переменная dataValue объявляется как объект типа id, поэтому dataValue можно использовать для хранения в программе объекта любого типа. Отметим, что в строке объявления не используется «звездочка»: id dataValue;

Объекту f 1 типа Fraction присваивается дробь 2/5, переменной с1 типа Complex присваивается значение (10 + 2.5i). Оператор dataValue = f 1;

сохраняет f1 в dataValue. Вы можете вызвать с dataValue любой из методов, допустимых в объекте типа Fraction, хотя dataValue имеет тип id, а не Fraction. Но как система определяет, какой метод нужно вызвать, если в dataValue можно сохранять объект любого типа? Если система встречает выражение с сообщением [dataValue print];

откуда она знает, какой метод print нужно вызвать? Ведь методы print определены и в классе Fraction, и в классе Complex.

Как уже говорилось, система Objective-C всегда следит за классом, которому принадлежит объект. Это также определяется концепциями динамического контроля типов и динамического связывания: система принимает решение о классе объекта и о методе для его динамического вызова во время выполнения, а не во время компиляции.

Поэтому во время выполнения программы, прежде чем передать dataValue сообщение print, система проверяет класс объекта, хранящегося в dataValue. В случае программы 9.2 эта переменная содержит объект типа Fraction, поэтому используется метод print, определенный в классе Fraction.

Во втором случае а с1 типа Complex присваивается dataValue. Затем выполняется следующее выражение с сообщением: [dataValue print];

Поскольку теперь dataValue содержит объект, принадлежащий классу Complex, для выполнения выбирается метод print из этого класса.

Это простой пример, но вы можете распространить эту концепцию на более сложные приложения. В сочетании с концепцией полиморфизма динамическое связывание и динамический контроль типов позволяют легко писать коды, которые передают одинаковое сообщение объектам из различных классов.

Например, метод draw можно использовать для рисования графических объектов на экране. У вас могут быть различные методы draw, определенные для каждого из ваших графических объектов, таких как тексты, окружности, прямоугольники, окна и т.д. Если графический объект, который нужно нарисовать, сохраняется, например, в переменной типа id с именем currentObject, то его можно нарисовать на экране, просто передав ему сообщение draw: [currentObject draw];

Вы можете сначала проверить, отвечает ли на метод draw объект, хранящийся в currentObject. Ниже вы увидите, как это делать. 9.3. Проверка на этапе компиляции и проверка на этапе выполнения

Поделиться:
Популярные книги

Вторая жизнь майора. Цикл

Сухинин Владимир Александрович
Вторая жизнь майора
Фантастика:
героическая фантастика
боевая фантастика
попаданцы
5.00
рейтинг книги
Вторая жизнь майора. Цикл

Гримуар темного лорда VI

Грехов Тимофей
6. Гримуар темного лорда
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Гримуар темного лорда VI

Первый среди равных. Книга III

Бор Жорж
3. Первый среди Равных
Фантастика:
попаданцы
аниме
фэнтези
6.00
рейтинг книги
Первый среди равных. Книга III

70 Рублей

Кожевников Павел
1. 70 Рублей
Фантастика:
фэнтези
боевая фантастика
попаданцы
постапокалипсис
6.00
рейтинг книги
70 Рублей

Архонт

Прокофьев Роман Юрьевич
5. Стеллар
Фантастика:
боевая фантастика
рпг
7.80
рейтинг книги
Архонт

Лейб-хирург

Дроздов Анатолий Федорович
2. Зауряд-врач
Фантастика:
альтернативная история
7.34
рейтинг книги
Лейб-хирург

Сэру Филиппу, с любовью

Куин Джулия
5. Бриджертоны
Любовные романы:
исторические любовные романы
8.08
рейтинг книги
Сэру Филиппу, с любовью

Кодекс Охотника. Книга XV

Винокуров Юрий
15. Кодекс Охотника
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Кодекс Охотника. Книга XV

Студиозус

Шмаков Алексей Семенович
3. Светлая Тьма
Фантастика:
юмористическое фэнтези
городское фэнтези
аниме
5.00
рейтинг книги
Студиозус

Локки 7. Потомок бога

Решетов Евгений Валерьевич
7. Локки
Фантастика:
аниме
эпическая фантастика
фэнтези
5.00
рейтинг книги
Локки 7. Потомок бога

Индульгенция 2. Без права на жизнь

Машуков Тимур
2. Темный сказ
Фантастика:
аниме
фэнтези
попаданцы
гаремник
5.00
рейтинг книги
Индульгенция 2. Без права на жизнь

Система Возвышения. (цикл 1-8) - Николай Раздоров

Раздоров Николай
Система Возвышения
Фантастика:
боевая фантастика
4.65
рейтинг книги
Система Возвышения. (цикл 1-8) - Николай Раздоров

Битва за Изнанку

Билик Дмитрий Александрович
7. Бедовый
Фантастика:
городское фэнтези
мистика
5.00
рейтинг книги
Битва за Изнанку

Горизонт Вечности

Вайс Александр
11. Фронтир
Фантастика:
боевая фантастика
космическая фантастика
космоопера
5.00
рейтинг книги
Горизонт Вечности