Программирование на Objective-C 2.0
Шрифт:
К настоящему моменту мы разработали небольшую библиотеку методов для работы с дробями. Ниже приводится файл секции interface, в котором применяется все, что мы умеем делать с использованием этого класса. #import <Foundation/Foundation.h> // Определение класса Fraction @interface Fraction : NSObject { int numerator; int denominator; } @property int numerator, denominator; -(void) print; -(double) convertToNum; -(Fraction *) add: (Fraction *) f; -(void) reduce; @end
Мы постепенно уточняли и расширяли класс путем добавления новых методов. Этот файл секции interface можно передать другому
Добавьте следующие методы к классу Fraction для завершения списка арифметических операций над дробями. Выполните сокращение (reduce) результата в каждом случае. // Вычитание аргумента из получателя -(Fraction *) subtract: (Fraction *) f; // Умножение получателя на аргумент -(Fraction *) multiply: (Fraction *) f; // Деление получателя на аргумент -(Fraction *) divide: (Fraction *) f;
Модифицируйте метод print из класса Fraction, чтобы он мог принимать необязательный аргумент типа B00L, который указывает, нужно ли выполнить сокращение дроби для ее вывода. Если дробь должна быть сокращена, сделайте так, чтобы сама дробь не изменялась необратимо.
Внесите изменения в программу 7.6, чтобы выводить результирующую сумму (sum) как дробь, а не только как вещественное число.
Будет ли ваш класс Fraction работать с отрицательными дробями? Например, можно ли сложить -1/4 и -1/2 и получить правильный результат? Напишите тестовую программу, чтобы проверить свой ответ.
Внесите изменения в метод print класса Fraction, чтобы выводить дроби, превышающие 1, как смешанные числа (с целой и дробной частями), например, дробь 5/3 выводить как 1 2/3.
В упражнении 6 главы 4 определяется новый класс с именем Complex для работы с комплексными мнимыми числами. Добавьте новый метод с именем add:, который можно использовать для сложения двух комплексных чисел. Чтобы сложить два комплексных числа, нужно по отдельности сложить вещественные и мнимые части: (5.3 + 7i) + (2.7 + 4i) = 8 + 11i Этот метод add: должен сохранять и возвращать результат в виде нового числа типа Complex в соответствии с объявлением метода: -(Complex *) add: (Complex *) complexNum; Учтите в тестовой программе все потенциальные проблемы утечки памяти.
Для класса Complex, разработанного в упражнении 6 главы 4, с учетом расширения, сделанного в упражнении 6 этой главы, создайте отдельные файлы секций interface и implementation —Complex.h и Complex.m. Создайте отдельный файл тестовой программы.
Глава 8. Наследование
В этой главе рассматривается один из ключевых принципов, который делает объектно-ориентированное программирование столь мощным. Принцип наследования позволяет расширять существующие определения классов и настраивать их для приложений. 8.1. Все начинается с корня
Мы уже рассматривали идею родительского класса в главе 3. Родительский класс может быть дочерним классом другого родительского класса. Класс, не имеющий никакого родительского класса, находится
Класс Fraction образуется из класса NSObject. Поскольку NSObject находится вверху иерархической структуры (то есть над ним уже нет никаких классов), он называется корневым классом (рис. 8.1). Класс Fraction является дочерним (child) классом или подклассом (subclass).
Рис. 8 .1. Корневой класс и подкласс
С точки зрения терминологии, можно говорить о классах, родительских классах и дочерних классах или о классах, подклассах и суперклассах. Если определяется какой-либо новый класс (не корневой), он наследует определенные свойства. Например, все переменные экземпляра и методы из родительского класса неявным образом становятся частью определения нового класса. Это означает, что соответствующий подкласс имеет непосредственный доступ к методам и переменным экземпляра, как будто они были определены непосредственно в определении этого подкласса.
Проиллюстрируем концепцию наследования с помощью простого (хотя и несколько надуманного) примера. Рассмотрим объявление объекта ClassA, содержащего один метод с именем initVar. @interface ClassA: NSObject { int x; } -(void) initVar; (@end
Метод initVar просто присваивает значение 100 переменной экземпляра класса ClassA. @implementation ClassA -(void) initVar { x = 100; } @end
Теперь определим класс с именем ClassB. @interface ClassB: ClassA -(void) printVar; @end
В первой строке этого объявления @interface ClassB: ClassA
указывается, что ClassB объяслвается не как подкласс NSObject, а как подкласс класса ClassA. И хотя родительским классом (суперклассом) для класса ClassA является NSObject, родительским классом для ClassB является ClassA (рис. 8.2). На этом рисунке корневой класс не имеет суперкласса, a ClassB, который находится внизу иерархии, не имеет подкласса. Тем самым ClassA является подклассом NSObject, ClassB является подклассом класса ClassA, а также класса NSObject (он является его «подподклассом», или внуком). Кроме того, NSObject является суперклассом для ClassA, который является суперклассом для ClassB. NSObject является также суперклассом для ClassB.
Ниже приводится полное определение для ClassB, где определяется один метод с именем printVar. @interface ClassB: ClassA -(void) printVar; @end (^implementation ClassB -(void) printVar { NSLog (@"x = %i", x); } @end
Метод printVar выводит значение переменной экземпляра х, и при этом мы не определяем никаких переменных экземпляра в ClassB. Поскольку ClassB является подклассом для ClassA, он наследует все переменные экземпляра из ClassA (в данном случае — только одну переменную). Это показано на рис. 8.3.