ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ В C++ (4-Е ИЗДАНИЕ) (часть 8) онлайн

Упражнения

Решения к упражнениям, помеченным знаком *, можно найти в приложении Ж. *1. Добавьте в класс Distance из программы ENGLPLUS этой главы перегру-                 женную операцию -, которая вычисляет разность двух интервалов. Она                 должна позволять выполнение выражений типа dist3=dist1-dist2;. Предпо-                 лагаем, что эта операция никогда не будет использоваться для вычитания                 большего интервала из меньшего (так как отрицательного интервала быть                 не может).

*2. Напишите программу, которая заменяет перегруженную операцию + на перегруженную операцию += в программе STRPLUS этой главы. Эта опера- ция должна позволять записывать выражения типа:

s1 += s2;

где s2 прибавляется (объединяется) к строке s1, результат при этом оста- ется в s1. Операция должна также позволять использовать результат для других вычислений, например в выражениях типа

s3 = s1 += s2;

*3. Модифицируйте класс time из упражнения 3 главы 6 так, чтобы вместо метода add_time() можно было использовать операцию + для складывания двух значений времени. Напишите программу для проверки класса.

*4. Создайте класс Int, основанный на упражнении 1 из главы 6. Перегрузите четыре целочисленных арифметических операции (+, -, * и /) так, чтобы их можно было использовать для операций с объектами класса Int. Если результат какой-либо из операций выходит за границы типа int (в 32- битной системе), имеющие значение от 2 14 7 483 648 до -2 147 483 648, то операция должна послать сообщение об ошибке и завершить про- грамму. Такие типы данных полезны там, где ошибки могут быть вы- званы арифметическим переполнением, которое недопустимо. Подсказ- ка: для облегчения проверки переполнения выполняйте вычисления с ис- пользованием типа long double. Напишите программу для проверки этого класса.

5. Пополните класс time, рассмотренный в упражнении 3, перегруженными операциями увеличения (++) и уменьшения (--), которые работают в обе- их, префиксной и постфиксной, формах записи и возвращают значение. Дополните функцию main(), чтобы протестировать эти операции,

6. Добавьте в класс time из упражнения 5 возможность вычитать значения времени, используя перегруженную операцию -, и умножать эти значе- ния, используя тип float и перегруженную операцию *.

7. Модифицируйте класс fraction в четырехфункциональном дробном каль- куляторе из упражнения 11 главы 6 так, чтобы он использовал перегру- женные операции сложения, вычитания, умножения и деления. (Вспом- ните правила арифметики с дробями в упражнении 12 главы 3 «Циклы и ветвления».) Также перегрузите операции сравнения == и != и используй- те их для выхода из цикла, когда пользователь вводит 0/1, 0 и 1 значения двух частей дроби. Вы можете модифицировать и функцию lowterms() так, чтобы она возвращала значение ее аргумента, уменьшенное до несократи- мой дроби. Это будет полезным в арифметических функциях, которые мо- гут быть выполнены сразу после получения ответа.

8. Модифицируйте класс bMoney из упражнения 12 главы 7 «Массивы и стро- ки», включив арифметические операции, выполненные с помощью пере- груженных операций:

ЬМоnеу = bMoney + ЬМоnеу ЬМоnеу = bMoney - ЬМоnеу

bМоnеу = bMoney * long double (цена за единицу времени, затраченного на изделие) long double = bMoney / ЬМоnеу (общая цена, деленная на цену за изделие) bMoney = ЬМоnеу / long double (общая цена, деленная на количество изделий)

Заметим, что операция / перегружена дважды. Компилятор может разли- чить оба варианта, так как их аргументы разные. Помним, что легче вы- полнять арифметические операции с объектами класса bMoney, выполняя те же операции с его long double данными.

Убедитесь, что программа main() запросит ввод пользователем двух де- нежных строк и числа с плавающей точкой. Затем она выполнит все пять операций и выведет результаты. Это должно происходить в цикле, так, чтобы пользователь мог ввести еще числа, если это понадобится.

Некоторые операции с деньгами не имеют смысла: bMoney*bMoney не пред- ставляет ничего реального, так как нет такой вещи, как денежный квад- рат; вы не можете прибавить bMoney к long double (что же будет, если рубли сложить с изделиями?). Чтобы сделать это невозможным, скомпилируйте такие неправильные операции, не включая операции преобразования для bMoney в long double или long double в bMoney. Если вы это сделаете и запи- шете затем выражение типа:

                bmon2 = bmon1+ widgets; //это не имеет смысла

то компилятор будет автоматически преобразовывать widgets в bMoney и выполнять сложение. Без них компилятор будет отмечать такие преобра- зования как ошибки, что позволит легче найти концептуальные ошибки. Также сделайте конструкторы преобразований явными.

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

                long double * bMoney // Пока не можем это сделать: bMoney возможен только справа                 long double / bMoney // Пока не можем это сделать: bMoney возможен только справа

Мы рассмотрим выход из этой ситуации при изучении дружественных функций в главе 11.

9. Дополните класс safearray из программы ARROVER3 этой главы так, чтобы пользователь мог определять и верхнюю, и нижнюю границы массива (например, индексы, начинающиеся с 100 и заканчивающиеся 200). Име- ем перегруженную операцию доступа к членам массива, проверяющую индексы каждый раз, когда к массиву нужен доступ, для проверки того, что мы не вышли за пределы массива. Вам понадобится конструктор с двумя аргументами, который определяет верхнюю и нижнюю границы. Так как мы еще не изучили, как выделять память динамически, то данные класса все еще будут размещаться в массиве, состоящем из 100 элементов, но вообще вы можете преобразовывать индексы массива safearray в индек- сы реального массива целых чисел произвольным образом. Например, ес- ли пользователь определил диапазон от 100 до 175, то вы можете преоб- разовать его в диапазон от arr[0] до arr[75].

10. Только для любителей математики: создайте класс Polar, который предна- значен для хранения полярных координат (радиуса и угла). Перегрузите операцию + для выполнения сложения для объектов класса Polar. Сложе- ние двух объектов выполняется путем сложения координат X объектов, а затем координат Y. Результат будет координатами новой точки. Таким образом, вам нужно будет преобразовать полярные координаты к прямо- угольным, сложить их, а затем обратно преобразовать прямоугольные ко- ординаты результата к полярным.

11. Помните структуру sterling? Мы встречались с ней в упражнении 10 гла- вы 2 «Основы программирования на C++», в упражнении 11 главы 5 и

в других местах. Преобразуйте ее в класс, имеющий переменные для фун- тов (типа long), шиллингов (типа int) и пенсов (типа int). Создайте в классе следующие функции:

конструктор без аргументов;

конструктор с одним аргументом типа double (для преобразования от десятичных фунтов);

конструктор с тремя аргументами: фунтами, шиллингами и пенсами;

метод getSterling() для получения от пользователя значений количества фунтов, шиллингов и пенсов в формате £9.19.11;

метод putSterling() для вывода значений количества фунтов, шиллин- гов и пенсов в формате £9.19.11;

метод для сложения (sterling + sterling), используя перегруженную опе- рацию +;

метод вычитания (sterling - sterling), используя перегруженную опера- цию -;

метод умножения (sterling * double), используя перегруженную опера- цию *;

метод деления (sterling / sterling), используя перегруженную опера- цию /;

метод деления (sterling / double), используя перегруженную опера- цию /;

операцию double (для преобразования к типу double)

 

Выполнять вычисления вы можете, например, складывая отдельно дан- ные объекта: сложить сначала пенсы, затем шиллинги и т. д. Однако легче использовать операцию преобразования для преобразования объекта клас- са sterling к типу double, выполнить вычисления с типами double, а затем преобразовать обратно к типу sterling. Таким образом, операция + выгля- дит похожей на эту:

sterling sterling::operator + (sterling s2) {

                return sterling (double (sterling (pounds, shillings, pense)) + double (s2)); }

Так мы создадим две временных переменных типа double, одна происхо- дит от объекта, который вызывает функцию, а другая от аргумента s2. Эти переменные затем складываются, результат преобразовывается к ти- пу sterling и возвращается.

Заметим, что мы использовали другой подход для класса sterling, нежели для класса bMoney. В классе sterling мы используем операции преобразова- ния, таким образом отказавшись от возможности поиска неправильных операций, но получив простоту при записи перегружаемых математиче- ских операций.

12. Напишите программу, объединяющую в себе классы bMoney из упражне- ния 8 и sterling из упражнения 11. Напишите операцию преобразования для преобразования между классами bMoney и sterling, предполагая, что один фунт (£1.0.0) равен пятидесяти долларам ($50.00). Это приблизи- тельный курс обмена для XIX века, когда Британская империя еще ис- пользовала меру фунты-шиллинги-пенсы. Напишите программу main(), которая позволит пользователю вводить суммы в каждой из валют и пре- образовывать их в другую валюту с выводом результата. Минимизируйте количество изменений в существующих классах bMoney и sterling.

 

 

36