Однако простое присвоение — это только начало. Скорее всего, вам потребуется использовать другие арифметические операторы, определяющие более интересное поведение. В табл. 8.1 показан перечень арифметических операторов и операторов присвоения.
Оператор | Поведение |
---|---|
= | Присвоение (должен быть функцией-членом) |
+ | Сложение |
- -= | Вычитание |
* *= | Умножение и разыменование |
/ /= | Деление |
% %= | Остаток от деления |
++ | Инкремент |
-- | Декремент |
^ ^= | Битовое исключающее ИЛИ |
~ | Битовое дополнение |
& &= | Битовое И |
| |= | Битовое ИЛИ |
<< <<= | Сдвиг влево |
>> >>= | Сдвиг вправо |
Для большинства операторов из табл. 8.1 существует две лексемы: первая — это версия оператора, используемая обычным образом, т.е. 1+2
x+=5
. Заметьте, что операторы инкремента и декремент ++
и --
описываются в рецепте 8.13.Реализация всех арифметических операторов и оператора присвоения очень похожа, за исключением оператора присвоения, который не может быть отдельной функцией (т.е. он должен быть методом).
Наиболее популярным при перегрузке является оператор сложения — благодаря тому что он может использоваться в отличных от математических контекстах, таких как объединение двух строк, так что давайте вначале рассмотрим именно его. Он складывает правый аргумент с левым и присваивает результирующее значение левому аргументу, как в выражении.
int i = 0;
i += 5;
После выполнения второй строки int i
Balance checking(500.00), savings(23.91);
checking += 50;
Это означает, что следует ожидать, что после использования оператора +=
checking
будет увеличено на 50. Именно это происходит при использовании реализации из примера 8.15. Посмотрите на определение функции для оператора +=
.Balance& operator+=(double other) {
val_ += other;
return(*this);
}
Для оператора присвоения список параметров — это то, что будет указано в операторе в его правой части. В данном случае используется целое число. Тело этой функции тривиально: все, что здесь делается, — это добавление аргумента к частной переменной-члену. Когда эта работа сделана, возвращается *this
*this
, что позволяет использовать их в выражениях, когда их результаты будут входом для чего-то еще. Например, представьте, что operator+= объявлен вот так.void operator+=(double other) { // Не делайте так
val += other;
}
Затем кто-то захочет использовать этот оператор для экземпляра класса и передать результат в другую функцию.
Balance moneyMarket(1000.00);
// ...
updateGeneralLeager(moneyMarket += deposit); // He скомпилируется
Это приведет к проблеме, так как Balance::operator+=
void
, а функция типа updateGeneralLedger
ожидает получить объект типа Balance. Если из арифметических операторов и оператора присвоения возвращать текущий объект, то этой проблемы не возникнет. Однако это верно не для всех операторов. Другие операторы, типа оператора элемента массива []
или оператора отношения возвращают объекты, отличные от *this
, так что это правило верно только для арифметических операторов и операторов присвоения.Здесь обеспечивается работа операторов присвоения, выполняющих какие-то вычисления, но как насчет вычислений без присвоения? Еще один способ использовать арифметические операторы выглядит так.
int i = 0, j = 2;
i = j + 5;
В этом случае к значению j
i
(при этом, если бы i
был объектом класса, а не встроенного типа, использовался бы оператор присвоения этого класса), а значение j
остается без изменения. Если требуется, чтобы класс вел себя точно так же, то перегрузите оператор сложения как самостоятельную функцию. Например, имеется возможность сделать так, чтобы можно было записать следующее.Balance checking(500.00), savings(100.00), total(0);
total = checking + savings;
Это делается в два этапа. Первый шаг — это создание функции, которая перегружает оператор +
Balance operator+(const Balance& lhs, const Balance& rhs) {