ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ В 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.
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
