При перегрузке операций для нового класса реализуйте сначала минимальный набор операций, а для реализации дополнительных операций используйте уже работающие.
Операции умножения на константу отличаются от операций деления только непосредственно знаком операции, поэтому приводить текст этих функций не будем.
И наконец, реализуем операции сравнения. Можно для этого использовать метод Сотра геМопеу () (см. листинг 1.15), сделав его закрытым, однако операции сравнения просты и обычно реализуются одна через другую. Результатом всех операций, естественно, будет значение типа boot. Тексты функций приведены в листинге 3.7.
Листинг 3.7. Операции сравнения
bool TMoney::operator==(const TMoney &b)
{ return (Summa == b.Summa); } // сравниваются числа
bool TMoney::operator!=(const TMoney &b)
{ return !(*this == b); // сравниваются деньги
bool TMoney::operator<(const TMoney &b)
{ return (Summa < b.Summa); } // сравниваются числа
bool TMoney::operator>=(const TMoney &b)
{ return !(*this < b); // сравниваются деньги
bool TMoney::operator>(const TMoney &b)
{ return !((*this < b)&&(*this == b)) // сравниваются деньги
bool TMoney::operator<=(const TMoney &b)
{ return (*this < b)||(*this == b); // сравниваются деньги
Проверка этих операций сложностей не представляет, поэтому оставляем ее читателю. Отметим только следующее: при реализации операций == и < в теле методов используются те же самые операции. Аналогичная картина наблюдается и при реализации других операций, например операции += (см. листинг 3.3). Вообще-то говоря, такая запись является рекурсивным вызовом, однако в данном случае рекурсии не возникает. Это объясняется типами аргументов: реализуются операции для денежного типа, а в теле функции они используются с аргументами встроенного типа long double.
Нам осталось реализовать всего несколько операций: ввода-вывода, инкремента и декремента. Рассмотрим более подробно операцию инкремента. Как известно, она имеет префиксную и постфиксную формы. Семантика этих форм несколько различается. Например:
double d = ++х;
Это присваивание выполняется так: х+=1;
double d = х;
Теперь постфиксная форма: double d = х++;
Постфиксная форма выполняется совершенно по-другому:
double d = х; х+=1;
Если мы заглянем в стандарт С++ (см. п. п. 13.5.7 в [1]), то обнаружим, что префиксная форма должна возвращать ссылку, а постфиксная — значение. Чтобы можно было отличить одно определение от другого, постфиксная форма операции должна иметь фиктивный аргумент типа int. Обе операции изменяют текущий объект. Пусть наш инкремент в префиксной окорме увеличивает сумму на 1 рубль, а в постфиксной — прибавляет одну копейку. В этом случае определения операций могли бы выглядеть так, как показано в листинге 3.8.
Листинг 3.8. Операции инкремента
TMoney& operator++()
{ return (*this+=100);
}
TMoney operator++(int) { TMoney t = *this;
*this+=l;
return t;
// префиксная форма
// увеличение рублей
// постфиксная форма
// увеличение копеек
}
Однако у нас не реализована операция сложения с присваиванием += для числового аргумента. Давайте реализуем более общий вариант — сложение с дробным числом типа long double. Выражение х+=1.0 тогда будет означать увеличение рублей, а выражение х+=0.01 — увеличение копеек. Если не проверять допустимость параметра, то определить операцию большого труда не составляет, что и продемонстрировано в листинге 3.9. Много работая необходимо не забывать о здоровье, на беговой дорожке можно похудеть.
Листинг 3.9. Реализация сложения с присваиванием дробного числа
ТМопеу& ТМопеу::operator+=(const long double &b)
{ Summa += round(b*100); // работает встроенная операция
return *this;
}
С учетом этой операции надо скорректировать соответствующие операторы в листинге 3.8:
// префиксный инкремент - для рублей // постфиксный инкремент - для копеек
*this+=1.0; *this+=0.01;
Проверка операции:
ТМопеу t = 2:
++t; t.DisplayMoneyO ;
t++; t.DisplayMoneyO ;
(++t).DisplayMoneyO; // без скобок - ошибка трансляции t++.DisplayMoneyO ;
Проверка показывает, что операции делают именно то, что мы и хотели. |