Private-Bookers
C++. Сборник рецептов
вернуться

Когсуэлл Джефф

Шрифт:

Пример 8.14. Перегрузка инкремента и декремента

#include <iostream>

using namespace std;

class Score {

public:

 Score : score_(0) {}

 Score(int i) : score_(i) {}

 Score& operator++ {

// префикс

++score_;

return(*this);

 }

 const Score operator++(int) {

// постфикс

Score tmp(*this);

++(*this); // Использование префиксного оператора

return(tmp);

 }

 Score& operator-- {

– -score_;

return(*this);

 }

 const Score operator--(int x) {

Score tmp(*this);

– -(*this);

return(tmp);

 }

 int getScore const {return(score_);}

private:

 int score_;

};

int main {

 Score player1(50);

 player1++;

 ++player1; // score = 52

 cout << "Счет = " << player1.getScore << '\n';

 (--player1)--; // score_ = 50

 cout << "Счет = " << player1.getScore << '\n';

}

Обсуждение

Операторы инкремента и декремента часто имеют смысл для классов, которые представляют некоторые разновидности целых значений. Если вы понимаете разницу между префиксной и постфиксной формами и следуете соглашениям о возвращаемых значениях, то их легко использовать.

Представьте себе инкремент целого числа. С помощью оператора

++
имеется два способа выполнить его для некоторого целого
i
.

i++; // постфиксный

++i; // префиксный

Оба инкрементируют

i
: первая версия создает временную копию
i
, инкрементирует
i
и затем возвращает временное значение, а вторая инкрементирует
i
и затем возвращает его. C++ позволяет выполнять перегрузку операторов, что означает, что вы можете заставить свой собственный тип (класс или
enum
) вести себя так же, как и
int
.

Чтобы добиться нужного эффекта, перегрузите

operator++
и
operator--
. Пример 8.14 иллюстрирует, как перегружать префиксную и постфиксную версии.

Score& operator++ { // префиксный

 ++score_;

 return(*this);

}

const Score operator++(int) { // постфиксный

 Score tmp(*this);

 ++(*this);

 return(tmp);

}

Префикс выглядит так, как и следует ожидать, но компилятор различает эти две версии, и в объявление постфиксной версии включается параметр

int
. Он не имеет семантического применения — он всегда передается как ноль, так что его можно игнорировать.

После этого класс

Score
можно использовать как
int
.

Score player1(50);

player1++;

++player1; // score_ = 52

Вы, вероятно, заметили, что сигнатуры префиксной версии

operator++
возвращают ссылку на текущий класс. Именно так и следует делать (а не возвращать, к примеру,
void
), чтобы инкрементируемый или декрементируемый объект мог использоваться в других выражениях. Рассмотрим такую строку из примера.

(--player1)--;

Да, это странно, но она иллюстрирует этот момент. Если бы префиксный

operator--
не возвращал чего-то осмысленного, то это выражение не скомпилировалось бы. Еще один пример показывает вызов функции.

foo(--player1);

Функция

foo
ожидает аргумент типа
Score
, и для корректной компиляции именно это должно возвращаться из префиксного
operator--
.

Перегрузка операторов — это мощная возможность, которая позволяет для типов, определяемых пользователем, использовать те же операторы, что и для встроенных типов. Сторонники других языков, которые не поддерживают перегрузку операторов, утверждают, что эта возможность сбивает с толку и очень сложна, и, следует признать, может быть перегружено очень много операторов, соответствующих любому поведению. Но когда дело касается простого инкремента и декремента, хорошо иметь возможность изменить поведение класса так, как этого хочется.

  • Читать дальше
  • 1
  • ...
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • ...

Private-Bookers - русскоязычная библиотека для чтения онлайн. Здесь удобно открывать книги с телефона и ПК, возвращаться к сохраненной странице и держать любимые произведения под рукой. Материалы добавляются пользователями; если считаете, что ваши права нарушены, воспользуйтесь формой обратной связи.

Полезные ссылки

  • Моя полка