Ответ
Чтобы перегрузить постфиксный инкремент (operator++(int)), нужно объявить метод с фиктивным параметром типа int. Этот параметр не используется, он служит только для отличия сигнатуры от префиксного инкремента (operator++()). Метод должен вернуть копию объекта до увеличения его значения.
#include <iostream>
class Integer {
private:
int value;
public:
Integer(int v) : value(v) {}
// Префиксный инкремент: ++obj
Integer& operator++() {
++value;
return *this; // Возвращаем ссылку на измененный объект
}
// Постфиксный инкремент: obj++
Integer operator++(int) {
Integer temp = *this; // Сохраняем текущее состояние
++value; // Инкрементируем внутреннее значение
return temp; // Возвращаем старое состояние
}
int getValue() const { return value; }
};
int main() {
Integer a(5);
Integer b = a++; // b = 5 (старое значение), a становится 6
Integer c = ++a; // a становится 7, c = 7 (новое значение)
std::cout << b.getValue() << std::endl; // 5
std::cout << c.getValue() << std::endl; // 7
return 0;
}
Ключевые отличия от префиксного инкремента:
- Сигнатура:
T operator++(int)vsT& operator++(). - Семантика: Возвращает значение до изменения.
- Эффективность: Постфиксный инкремент обычно менее эффективен из-за необходимости создания и возврата временного объекта. Поэтому в циклах
forпредпочтительнее использовать префиксную форму (++i).
Ответ 18+ 🔞
А, ну это же классика, ёпта! Сидишь такой, пишешь свой класс, всё красиво, а потом бац — надо перегрузить инкремент. И тут начинается: а какой из них какой, блядь?
Смотри, история простая, но хитрая, как жопа. Есть два инкремента: один делает дело и сразу говорит "я готов" (это префиксный, ++obj), а второй сначала говорит "я какой был", а потом уже делает дело (это постфиксный, obj++). Компилятору-то надо как-то их различать, а имена-то у методов одинаковые — operator++. Вот и придумали гениальный костыль, ядрёна вошь.
Для постфиксного инкремента в сигнатуру метода пихают фиктивный параметр типа int. Просто так, для галочки. Никакого смысла в нём нет, это как соль в кармане — от сглазу. Внутри метода ты должен:
- Сохранить текущее состояние объекта (сделать копию) — это будет "старое значение".
- Увеличить своё внутреннее поле (то есть сделать то, ради чего всё и затевалось).
- Вернуть ту самую сохранённую копию, которая уже устарела, но кому-то нужна.
// Постфиксный инкремент: obj++
Integer operator++(int) {
Integer temp = *this; // Шаг 1: Сохраняем себя прежнего. "Смотрите, какой я был красавчик!"
++value; // Шаг 2: А теперь реально увеличиваемся. Дело сделано.
return temp; // Шаг 3: Возвращаем того, старого. "На, полюбуйся, но это уже не я".
}
А префиксный (++obj) — он без этого дурацкого int, работает напрямую, меняет себя и сразу возвращает ссылку на изменённого себя. Быстро и эффективно.
И вот главный подвох, из-за которого все путаются: постфиксный инкремент обычно менее эффективен, ёб твою мать! Потому что он создаёт лишнюю копию объекта. В примере с int — пофиг, а если объект на 500 байт? Копирование — это овердохуища лишней работы.
Поэтому все опытные ребята в циклах for пишут ++i, а не i++. Разница в скорости может быть, а может и не быть, но принцип-то, блядь, правильный! Зачем создавать временный объект, если можно без него?
Короче, запомни: int в скобках — это волшебный пендель для компилятора, который говорит "эй, это тот инкремент, который возвращает старое значение, и он медленнее, потому что копирует". Всё, больше ни хуя не нужно.