View in Telegram
​​Различаем преинкремент и постинкремент #новичкам Новичкам всегда не просто даются перегрузки операторов. Не то, чтобы кому-то часто приходится перегружать операторы. Но уж эти *нкременты точно редко. Из-за этого особенности постоянно забываются. Давайте же во всем разберемся. Есть операторы инкремента и декремента. Первые увеличивают значение на какую-то условную единицк, вторые - уменьшаю. Они подразделяются на 2 формы: пре- и пост-. Далее будем все разбирать на примере операторов инкремента, для декремента все аналогично, только меняете плюс на минус. Преинкремент - увеличивает значение на единицу и возвращает ссылку на уже увеличенное значение. Синтаксис использования такой: ++value. Постинкремент - делает копию исходного числа, увеличивает на единицу оригинал, и возвращает копию по значению. Синтаксис использования такой: value++. Обычно внешний вид перегрузки операторов внутри описания класса такой: возвращаемое_значение operator{символы_вызова_оператора}(аргументы). Например, оператор копирования вызывается с помощью оператора присваивания(=). Поэтому подставляем в шаблон на место возвращаемое_значение ссылку на объект, на место символы_вызова_оператора подставляем =, на место аргументов - const Type&. Получается так:
Type& operator=(const Type&);
Но теперь возникает вопрос. С++ не различает функции, у которых то же имя, то же те же аргументы, но разные возвращаемые значения. У нас как раз такая ситуация: названия одинаковые(operator++), возвращаемые значения разные(в одном случае возвращаем по ссылке, во втором - по значению) и одинаково отсутствуют аргументы. Если бы мы определили операторы так:
Type& operator++() {
  value_ += 1;
  return *this;
}

Type operator++() {
  auto tmp_value = *this;
  value_ += 1;
  return tmp_value;
}
То была бы примерно такая ошибка компиляции: functions that differ only in their return type cannot be overloaded. Что же делать? Примерно таким же вопросом задался Страуструп и сделал ход конем(правда конь ходил на костылях). Он связал префиксный оператор с человеческой формой объявления, а постфиксный - с вот такой:
Type operator++(int) {
  auto tmp_value = *this;
  value_ += 1;
  return tmp_value;
}
Он ввел безымянный интовый параметр функции. Теперь чисто технически, компилятор сможет различить 2 вызова этих операторов и правильно заметчить эти вызовы на нужные определения. Если видит префикс - выбирает оператор без аргумента, видит постфикс - выбирает с аргументом. Вопрос, почему тип аргумента именно int - остается открытым. Наверное так было проще. Итого, так перегружаются операторы инкремента:
struct Type {
  Type& operator++() {
    value_ += 1;
    return *this;
  }
  
  Type operator++(int) {
    auto tmp_value = *this;
    value_ += 1;
    return tmp_value;
  }
private:
  IntegerLikeType value_;
};
Think of your decisions twice. Stay cool. #cppcore
Love Center
Love Center
Find friends or serious relationships easily