Остальные операции со структурой перегружаются аналогичным образом, поэтому не будем на этом останавливаться — нас больше интересует перегрузка операций как методов класса. Вернемся к нашему классу ТМопеу. Хотя методов у нас было немного, операций мы можем реализовать гораздо больше, что позволит оперировать денежными суммами более естественными способами. Во-первых, перегрузим в виде операций уже реализованные нами методы сложения, вычитания, умножения и деления. Помимо обычных операций, реализуем те же операции с присваиванием, а также инкремент и декремент. Во-вторых, вместо одного метода сравнения лучше реализовать обычные операции сравнения. И в-третьих, операции ввода-вывода тоже лучше иметь в привычном для С++ виде.
Как мы помним, у методов один параметр — текущий объект — определен по умолчанию. Поэтому унарные операции выполняются для текущего объекта, который и является единственным аргументом. Следовательно, при перегрузке как методы класса они не имеют параметров. Заголовок унарной операции, реализованной как метод класса, выглядит так:
тип operator@() ^
Здесь @ — символ операции.
ПРИМЕЧАНИЕ
Постфиксные операции инкремента и декремента являются исключением из этого правила. Для того чтобы отличить постфиксную операцию от префиксной, в постфиксной операции прописывают фиктивный аргумент, который реально не используется.
Заголовок бинарной операции, соответственно, имеет один аргумент и выглядит так:
тип operator@(napaMeTp)
Параметры тем не менее разрешается передавать любым удобным нам способом: по значению, по ссылке или по указателю. Вызов унарной операции для объекта t выглядит так:
@t t@
Вариант выбирается в зависимости от того, какой вид операции определен: префиксный или постфиксный. Функциональная форма вызова выглядит одинаково для обоих вариантов:
t.operator@()
Функциональная форма вызова для бинарной операции, определенной как метод класса, выглядит аналогично:
t.operator@(p)
Такая запись подчеркивает, что у бинарной операции, перегружаемой методом класса, только один параметр, так как левым аргументом обязательно должен быть объект определяемого класса. Инфиксная форма:
t @ р
Эта форма фактически является просто сокращением функциональной — удалены конструкция .operator и скобки вокруг второго аргумента.
Рассмотрим реализацию операции сложения денежных сумм. Внешнее определение, представленное в листинге 3.3, ничем, за исключением заголовка, не отличается от реализованного нами ранее метода AddMoney () (см. листинг 1.12), в котором аргументом является тоже объект типа TMoney.
Листинг 3.3. Метод-операция сложения денежных сумм
TMoney TMoney::operator+(const TMoney &b) { TMoney t = Uhis:
t.Summa += b.Summa: // работает встроенная операция
return t;
}
Теперь мы, наконец, сможем писать сложение денежных сумм в привычном виде: а = b + с;
Вывод суммы на экран можно осуществлять, не сохраняя результат в переменной: (t+p) .DisplayMoneyO ;
Выглядит необычно, но перепишем вызов операции в функциональной форме: (t.operator+(p)).DisplayMoneyO;
Совершенно очевидно, что это выражение эквивалентно описанному ранее в листинге 1.17 (помечено цифрой 1):
(t.AddMoney(р)).DisplayMoneyO:
Перегрузим теперь операцию сложения с присваиванием (+=). Желательно, чтобы семантика перегруженной операции совпадала с семантикой встроенной: программист в этом случае совершает меньше ошибок при ее использовании. Если у вашего сайта частые проблемы с вирусами, то ему необходим мониторинг сайта на шеллы тут. Напомним семантику встроенной операции: значение правого аргумента складывается со значением левого аргумента, и результат опять помещается в левый аргумент. Так как операция бинарная, то в заголовке должен быть указан один параметр. Левым аргументом у нас является текущий объект, а правым — параметр метода-операции. Таким образом, эта операция должна изменять значения полей текущего объекта. |