В главе 1 (см. листинг 1.15) мы реализовали два метода AddMoneyO: сложение денег с деньгами и сложение денег с дробной константой, которая в этом случае представляет собой денежную сумму-константу. Перепишем теперь «простое» сложение с одним аргументом — дробным числом (листинг 3.10).
Листинг 3.10. Операция сложения с дробным числом
TMoney TMoney::operator+(const long double &b) { TMoney t=*this;
t+=round(b*100); // работает реализованная нами операция
return t;
}
Обратите внимание на то, что в следующем операторе из листинга 3.9 операция += выполняется с переменными типа long double, поэтому работает встроенная операция:
Summa += round(b*100); // работает встроенная операция
В листинге же 3.10 действия выполняются с денежными суммами, поэтому работает реализованный в классе TMoney метод-операция:
t+=round(b*100); // работает реализованная нами операция
Полиморфизм — в действии!
Однако при проверке реализованной операции сложения неожиданно оказывается^ что вторая строка вызывает ошибку трансляции:
s = t+2; s.DisplayMoneyO ;
s = 2+t; s.DisplayMoneyO; // ошибка трансляции!
Ситуацию проясняет функциональная запись. Первое выражение запишется так: s = t.operator+(2);
Второе же выражение ошибочно, так как левый аргумент не является объектом типа TMoney:
s = 2.operator+(t);
Получается, что операция сложения, реализованная как метод класса, не является коммутативной! Точно такая же ситуация с уже реализованной нами операцией умножения на число:
s = t*2; s.DisplayMoneyO; // работает
s = 2*t; s.DisplayMoneyO; // не работает!
Теперь рассмотрим операции ввода-вывода1« и ». Обе операции перегружают изначально определенные в языке С операции сдвига влево и вправо, поэтому операции ввода-вывода — бинарные, как и сдвиги (см. п. 5.8 в [1]). Операции ввода-вывода, очевидно, являются операциями многократными, поэтому должны возвращать ссылку. Однако самым важным является не это. Левым аргументом у операции ввода является объект ci п типа i stream, а у операции вывода — объект cout типа ostream. Реализовав ввод-вывод методами класса TMoney, мы не сможем этого обеспечить, поскольку левым аргументом любого метода является
Подробности см. в главе 14.
объект «своего» типа. Давайте тем не менее попробуем реализовать, например, операцию вывода и посмотрим, что из этого выйдет. У функции-метода, очевидно, должен быть один явный параметр — поток вывода. Реализация метода почти совпадает с реализацией метода-функции DisplayMoneyO за исключением того, что должна возвращаться ссылка на объект типа ostream. Таким образом, возможная реализация выглядит так, как показано в листинге 3.11. Если у вас сломался ковш на экскаваторе, то например http://z-mg.ru/Tooth/Tooth.aspx здесь недорого.
Листинг 3.11. Вывод как метод класса
ostream& ТМопеу::operator<<(ostream& t) { string s = toStringO ; s+=" руб.";
return (t << s << endl);
}
Определение вопросов не вызывает, однако вызов операции вывода сбивает с толку:
d << cout: // запись "наоборот"
Хотя операция работает совершенно правильно, это совсем не то, что мы хотели. Проблема именно в том, что левым аргументом метода должен быть текущий объект. В функциональной форме записи это отчетливо видно:
d.operator<<(cout);
Аналогичная картина наблюдается и при реализации операции ввода. |