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

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

Жанры

Программирование на 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. Проверка на этапе компиляции и проверка на этапе выполнения

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

Господин Хладов

Шелег Дмитрий Витальевич
4. Кровь и лёд
Фантастика:
аниме
5.00
рейтинг книги
Господин Хладов

Жизнь в подарок

Седой Василий
2. Калейдоскоп
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Жизнь в подарок

Печать пожирателя 2

Соломенный Илья
2. Пожиратель
Фантастика:
городское фэнтези
попаданцы
аниме
сказочная фантастика
5.00
рейтинг книги
Печать пожирателя 2

Копиист

Поселягин Владимир Геннадьевич
2. Рунный маг
Фантастика:
фэнтези
7.26
рейтинг книги
Копиист

Меченный смертью. Том 2

Юрич Валерий
2. Меченный смертью
Фантастика:
аниме
фэнтези
попаданцы
5.00
рейтинг книги
Меченный смертью. Том 2

Третий

INDIGO
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
Третий

На границе империй. Том 5

INDIGO
5. Фортуна дама переменчивая
Фантастика:
боевая фантастика
попаданцы
7.50
рейтинг книги
На границе империй. Том 5

Звездная Кровь. Изгой II

Елисеев Алексей Станиславович
2. Звездная Кровь. Изгой
Фантастика:
боевая фантастика
попаданцы
технофэнтези
рпг
5.00
рейтинг книги
Звездная Кровь. Изгой II

Светлая тьма. Советник

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

#Бояръ-Аниме. Газлайтер. Том 11

Володин Григорий Григорьевич
11. История Телепата
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
#Бояръ-Аниме. Газлайтер. Том 11

Как я строил магическую империю 5

Зубов Константин
5. Как я строил магическую империю
Фантастика:
попаданцы
аниме
фантастика: прочее
фэнтези
5.00
рейтинг книги
Как я строил магическую империю 5

Ученик

Листратов Валерий
2. Ушедший Род
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Ученик

Газлайтер. Том 31

Володин Григорий Григорьевич
31. История Телепата
Фантастика:
боевая фантастика
попаданцы
альтернативная история
фэнтези
5.00
рейтинг книги
Газлайтер. Том 31

Петля, Кадетский корпус. Книга третья

Алексеев Евгений Артемович
3. Петля
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Петля, Кадетский корпус. Книга третья