Member 12975649 Ответов: 3

Перегрузка постфиксного оператора ++


#include <iostream>
using namespace std;

class Time {
private:
	int hours;             // 0 to 23
	int minutes;           // 0 to 59
public:
	// required constructors
	Time(){
		hours = 0;
		minutes = 0;
	}
	Time(int h, int m){
		hours = h;
		minutes = m;
	}
	// method to display time
	void displayTime() {
		cout << "H: " << hours << " M:" << minutes << endl;
	}

	Time& operator++()
	{
		++minutes;
		if (minutes>=60)
		{
			++hours;
			minutes = minutes - 60;
		}
		return *this;
	}

	Time& Time::operator++(int){
		
		Time temp(hours, minutes);
		minutes++;
		if (minutes >= 60)
		{
			hours++;
			minutes = minutes - 60;
		}
		return *this;
	}
	
};

int main() {
	Time T1(11, 59), T2(10, 40);

	T2 = ++(++T1); // 
	T1.displayTime();        // display 12,01 ok
	T2.displayTime();        // display 12,01 ok

	T2 = (T1++)++;           
	T1.displayTime();        // display 12,03 οκ
	T2.displayTime();        // display 12,03 why?? i think it must be 12,01

	return 0;
}


Что я уже пробовал:

Проблема заключается в объекте T2

Philippe Mori

Вы почти всегда должны следовать предопределенным сигнатурам операторов при перегрузке оператора. Постфиксный оператор должен быть объявлен как Time operator++(int) Всегда полезно прочитать документацию перед написанием кода, а не гадать, а затем гадать, почему код не работает.

Philippe Mori

Кстати, на мой взгляд, не стоит перегружать оператор ++ в этом случае, так как может быть не очевидно, что инкремент равен 1 минуте. Что делать, если в какой-то момент Вы решите, что время должно иметь разрешение 1 секунда. Лучше быть явным, и это облегчит обслуживание вашего кода.

Philippe Mori

Кроме того, ваши комментарии о отображаемых значениях не соответствуют фактическому коду. Ваш код будет отображать H: 12M: 1. Если вы потратите время на то, чтобы написать то, что выводит код, по крайней мере, приложите усилия, чтобы соответствовать фактическому выходу. 

3 Ответов

Рейтинг:
1

KarstenK

Это правильно по вашему коду:

T2 = ++(++T1);

1. вы увеличиваете T1 в фигурных скобках
2. вы увеличиваете T1 вне фигурных скобок
3. Вы назначить от значений T1 до T2

совет: используйте отладчик для выполнения шага в три вызова функций этой строки кода.


Member 12975649

@KarstenK но я хочу двойной постфикс ++ а не префикс! спасибо

Рейтинг:
1

Jochen Arndt

Ваша реализация постфиксного оператора неверна. Вы должны вернуться temp (неизмененный объект) вместо измененного объекта:

Time operator++(int)
{
    Time temp(hours, minutes);
    minutes++;
    if (minutes >= 60)
    {
        hours++;
        minutes = minutes - 60;
    }
    // Return unchanged object here!
    return temp;
}

Смотреть также Перегрузка операторов инкремента и декремента (C++)[^].
Это использует префиксное приращение в постфиксной реализации:
Time operator++(int)
{
    Time temp = *this;
    *++this;
    return temp;
}


Philippe Mori

Но в этом случае вы также должны возвращать время по значению.

Jochen Arndt

Спасибо за поправку.

Philippe Mori

Поэтому исправьте свой код, удалив ссылку: Time operator++(int).

Рейтинг:
0

Richard MacCutchan

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


Member 12975649

@Richard MacCutchan T2 = (T1++)++; можете ли вы сказать мне, какие действия шаг за шагом происходят?

Richard MacCutchan

Вы можете сделать это сами, пройдя через код с помощью своего отладчика. как я уже предлагал.

Member 12975649

спасибо за твою помощь, парень!

Richard MacCutchan

Смотреть также Общие правила перегрузки операторов[^].

Philippe Mori

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

Я думаю, что единственными операторами, для которых пользовательский оператор изменяет способ вычисления выражения, являются && и || поскольку оценка короткого замыкания не работает в этом случае, поскольку обе стороны должны быть оценены перед вызовом функции оператора.

Для любых других операторов основным проблемным случаем является то, что одна и та же переменная используется несколько раз в выражении, в котором нет точки последовательности... Такая же проблема может возникнуть и с пользовательскими функциями.

Richard MacCutchan

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