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

ЖАНРЫ

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

Цикл for начинается с 1 и продолжается до значения п. На каждом шаге цикла aFraction присваивается значение 1/pow2, то есть 1/2i. Это значение затем добавляется к сумме (sum) с помощью определенного ранее метода add:. Значение result, возвращаемое из add:, присваивается sum2, а не sum, чтобы избежать проблем утечки памяти. (А что произойдет, если присвоить result непосредственно sum?) Старое значение sum затем освобождается, и для следующего шага цикла sum присваивается новое значение суммы — sum2. Изучите, каким образом здесь происходит освобождение памяти для дробей. Для цикла for, который выполняется сотни или тысячи раз, при неверном освобождении памяти для

дробей у вас быстро накопится большой объем неиспользуемой памяти.

По окончании цикла for конечный результат выводится в виде десятичного значения с помощью метода convertToNum. Остается только освободить два объекта: aFraction и конечный объект типа Fraction, сохраненный в sum. После этого завершается выполнение программы.

Результаты вывода показывают, что происходит при запуске программы. При значении 5 сумма последовательности равна 0.96875. При 15 результат очень близок к 1. Расширение определений класса и файл секции interface

К настоящему моменту мы разработали небольшую библиотеку методов для работы с дробями. Ниже приводится файл секции 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. Родительский класс может быть дочерним классом другого родительского класса. Класс, не имеющий никакого родительского класса, находится вверху иерархии и называется корневым классом (root class). В Objective-C вы можете определять собственный родительский класс, но обычно используют возможности существующих классов. Все классы, которые мы определяли до настоящего момента, являются дочерними классами (потомками) корневого класса с именем NSObject, который указывался в файле секции interface следующим образом: @interface Fraction: NSObject @end

Класс 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.

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