Перегрузка оператора ввода C ++ & quot; & gt; & quot;

У меня класс рациональных чисел состоит из двух целых чисел: numНоминатор и denзнаменатель.

Следующий оператор должен считать рациональное число из потока.

istream& operator >> (istream& Is, rational& r) {
char c; //Test char.
double n; //Could be either the numerator of the fraction or the antiperiod of the repeating decimal number.
Is >> n;
int i = 0;
for (; n*10-pow(10, i+1) < 1 && int(n) != 0; i++) {
n *= 10;
}
for (; int(n*10) % 10; i++) {
n *= 10;
}
n /= pow(10, i);
if (i == 0) {
r.num = n;
Is >> ws;
c = Is.peek();
if (c == '/') {
c = Is.get();
Is >> r.den;
} else {
r.den = 1;
}
r.normalize(); //This function normalizes the fraction.
} else {
Is >> ws;
c = Is.peek();
if (c == 'p' || c == 'P') {
int p; //Period of the repeating decimal number.
c = Is.get();
Is >> p;
vector<int> a = genFrac(n, p); //This function returns the fraction which express the decimal repeating number. It returns a "vector<int>" with the nominator at index 1 e denominator at index 0.
r.num = a[1];
r.den = a[0];
} else {
i = 0;
for (; n*10-pow(10, i+1) < 1 && int(n) != 0; i++) {
n *= 10;
}
for (; int(n*10) % 10 != 0; i++) {
n *= 10;
}
int pot10 = pow(10, i);
r.num = n;
r.den = pot10;
}
r.normalize();
}
return Is;
}

Я написал этот код для реализации ввода моего «рационального» класса.
Я изменил его по сравнению с тем, что написано в моей книге по C ++, чтобы сделать возможным ввод десятичных чисел, в том числе повторяющихся.

Он должен уметь обрабатывать следующие типы ввода:

  • 9/8
  • 9
  • 9,87
  • 1.p3 (= 1.3333333333)

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

Может кто-нибудь мне помочь?

6

Решение

Я думаю, я бы написал это несколько иначе1.

Если вам действительно не нужно делать иначе, я бы начал с чтения целого «чанка» ввода (т. Е. Всех символов до следующего пробела), затем выяснил, как это должно представлять число, и вызвал бы отдельный функция для каждого возможного представления:

std::istream &operator>>(std::istream &is, rational &r) {
std::string temp;

Is >> temp;
if (temp.find('/') != std::string::npos)
r = cvt_fraction(temp, Is);
else if (temp.find_first_of("pP") != std::string::npos)
r = cvt_repeating(temp, Is);
else if (temp.find('.') != std::string::npos)
r = cvt_float(temp, Is);
else
r = cvt_int(temp, Is);
return Is;
}

Я передал istream каждому по двум причинам: во-первых, если они находят мусор во входных данных, они могут установить бит сбоя потока. Во-вторых, так если им действительно нужно читать больше входных данных, они могут (но я был бы немного удивлен, если это когда-либо действительно необходимо).

Мне кажется, что каждая из этих функций преобразования должна быть довольно тривиальной: если я начинаю с того факта, что строка должна быть digits "/" digits или `digits» p «digits», выполнение преобразования, как правило, будет довольно простым — в частности, достаточно простым, так что я думаю, что любой может взглянуть на код и разобраться, что должен делать каждый фрагмент.


  1. Честно говоря, я не хочу быть противным, но если бы я поддерживал код и наткнулся на ваш operator>>У меня была бы одна из двух возможных реакций: если она, очевидно, имела ошибку, немедленно замените ее. В противном случае внесите его в список «технических долгов» и замените его как можно скорее. Простой факт заключается в том, что в том виде, в каком оно существует сейчас, требуется немало усилий, чтобы даже убедиться, какие входные форматы должны поддерживаться, не говоря уже о том, какая часть кода обрабатывает каждый, или как все это должно делать. работать вместе, чтобы получить значимый результат.
5

Другие решения

Проблема, упомянутая в комментарии ( p не появляется в c=is.peek() заявление) исходит из того факта, что p на самом деле хранится в ws (хранится там в is >> ws).

Приведенный выше код также не содержит упоминаний ws, но я предполагаю, что это char,

1

По вопросам рекламы [email protected]