Урок 137. Перегрузка операторов инкремента и декремента

   ⁄ 

 Обновлено 17 Апр 2018  ⁄ 

⁄   114

Перегрузка операторов инкремента (++) и декремента (−−) довольно проста, но с одним маленьким нюансом. Есть две версии операторов инкремента и декремента: префикс (например: ++x, --y) и постфикс (например: x++, y--).

Поскольку операторы инкремента и декремента являются унарными и изменяют свои операнды, то перегрузку следует выполнять через методы класса.

Перегрузка операторов инкремента и декремента версии префикс

Перегрузка операторов инкремента и декремента версии префикс аналогична перегрузке любых других унарных операторов:

Здесь класс Number содержит число от 0 до 8. Мы перегрузили операторы инкремента/декремента таким образом, чтобы они увеличивали/уменьшали m_number в соответствии с заданным диапазоном (если выполняется инкремент и m_number равно 8, то сбрасываем значение m_number на 0; если выполняется декремент и m_number равно 0, то присваиваем значение 8 переменной m_number).

Результат выполнения программы выше:

78087

Обратите внимание, мы возвращаем скрытый указатель *this в функциях перегрузки операторов (т.е. текущий объект класса Number). Таким образом, мы можем связать выполнение нескольких операторов в одну «цепочку».

Перегрузка операторов инкремента и декремента версии постфикс

Обычно, перегрузка функций осуществляется, если они имеют одно и то же имя, но разное количество и типы параметров (детальнее о перегрузке функций в уроке 102). Рассмотрим случай с операторами инкремента/декремента версий префикс/постфикс. Оба имеют одно и то же имя (например, operator++), унарные и принимают один параметр одного и того же типа данных. Как же тогда их различить при перегрузке?

Дело в том, что C++ использует «фиктивную переменную» или «фиктивный параметр» для операторов версии постфикс. Этот фиктивный целочисленный параметр используется только с одной целью: отличить версию постфикс операторов инкремента/декремента от версии префикс. Перегрузим версии префикс и постфикс операторов инкремента/декремента в одном классе:

Результат:

6778776

Здесь есть несколько интересных моментов:

  Во-первых, мы разделили версию постфикс от версии префикс использованием целочисленного фиктивного параметра в версии постфикс.

  Во-вторых, поскольку фиктивный параметр не используется в реализации самой перегрузки, то мы даже не даём ему имя. Таким образом, компилятор будет рассматривать эту переменную как простую заглушку (заполнитель места) и даже не будет предупреждать нас, что мы объявили переменную, но никогда её не использовали.

  В-третьих, операторы версий префикс и постфикс выполняют одно и то же задание — оба увеличивают/уменьшают значение переменной объекта. Разница между ними только в значении, которое они возвращают.

Рассмотрим последний пункт детальнее. Операторы версии префикс возвращают объект после того, как он был увеличен или уменьшен. В версии постфикс нам нужно возвращать объект до того, как он будет увеличен или уменьшен. И тут конфуз! Если мы увеличиваем или уменьшаем объект, то мы не можем возвратить его до выполнения инкремента/декремента, так как операция увеличения/уменьшения уже произошла. С другой стороны, если мы возвращаем объект до выполнения инкремента/декремента, то сама операция увеличения/уменьшения объекта не выполниться.

Решение — использовать временный объект с текущим значением переменной-члена. Тогда можно будет увеличить/уменьшить исходный объект, а возвратить обратно в caller временный объект. Таким образом, caller получит копию объекта до того, как фактический объект будет увеличен или уменьшен, и сама операция инкремента/декремента пройдет успешно.

Обратите внимание, это означает, что возврат значения по ссылке невозможен, так как мы не можем возвратить ссылку на локальную переменную (объект), которая будет уничтожена после завершения выполнения тела функции. Также это означает, что операторы версии постфикс обычно менее эффективны, чем операторы версии префикс, из-за дополнительных расходов ресурсов на создание временного объекта и выполнения возврата по значению вместо возврата по ссылке.

Наконец, мы реализовали перегрузку операторов версии постфикс через уже перегруженные операторы версии префикс. Таким образом, мы сократили дублированный код и упростили внесение изменений в наш класс в будущем (т.е. упростили поддержку кода).

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (2 оценок, среднее: 5,00 из 5)
Загрузка...
Подписаться на обновления:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

ПОДПИСЫВАЙТЕСЬ

НА КАНАЛ RAVESLI В TELEGRAM

@ravesli

ПОДПИСАТЬСЯ БЕСПЛАТНО