Литмир - Электронная Библиотека
A
A

10.11.2. Считывание структурированных значений

Класс

Reading
будет использован только для ввода данных, к тому же он намного проще остальных

struct Reading {

  int day;

  int hour;

  double temperature;

};

istream& operator>>(istream& is, Reading& r)

  // считываем показания температуры из потока is в объект r

  // формат: (3 4 9.7)

  // проверяем формат, но не корректность данных

{

  char ch1;

  if (is>>ch1 && ch1!='('){ // можно это превратить в объект типа

                            // Reading?

    is.unget();

    is.clear(ios_base::failbit);

    return is;

  }

  char ch2;

  int d;

  int h;

  double t;

  is >> d >> h >> t >> ch2;

  if (!is || ch2!=')') error("Плохая запись"); // перепутанные

                                               // показания

  r.day = d;

  r.hour = h;

  r.temperature = t;

  return is;

}

В принципе мы проверяем, правильно ли начинается формат. Если нет, то переводим файл в состояние

fail()
и выходим. Это позволяет нам попытаться считать информацию как-то иначе. С другой стороны, если ошибка формата обнаруживается после считывания данных и нет реальных шансов на возобновление работы, то вызываем функцию
error()
.

Операции ввода в классе

Month
почти такие же, за исключением того, что в нем вводится произвольное количество объектов класса
Reading
, а не фиксированный набор значений (как делает оператор
>>
в классе
Reading
).

istream& operator>>(istream& is, Month& m)

  // считываем объект класса Month из потока is в объект m

  // формат: { month feb... }

{

  char ch = 0;

  if (is >> ch && ch!='{') {

    is.unget();

    is.clear(ios_base::failbit); // ошибка при вводе Month

    return is;

  }

  string month_marker;

  string mm;

  is >> month_marker >> mm;

  if (!is || month_marker!="month") error("Неверное начало Month");

  m.month = month_to_int(mm);

  Reading r;

  int duplicates = 0;

  int invalids = 0;

  while (is >> r) {

    if (is_valid(r)) {

      if (m.day[r.day].hour[r.hour] != not_a_reading)

      ++duplicates;

      m.day[r.day].hour[r.hour] = r.temperature;

    }

    else

      ++invalids;

  }

  if (invalids) error("Неверные показания в Month", invalids);

  if (duplicates) error("Повторяющиеся показания в Month",
duplicates);

  end_of_loop(is,'}',"Неправильный конец Month");

  return is;

}

Позднее мы еще вернемся к функции

month_to_int();
она преобразовывает символические обозначения месяцев, такие как
jun
, в число из диапазона
[0:11]
. Обратите внимание на использование функции
end_of_loop()
из раздела 10.10 для проверки признака завершения ввода. Мы подсчитываем количество неправильных и повторяющихся объектов класса
Readings
(эта информация может кому-нибудь понадобиться).

Оператор

>>
в классе
Month
выполняет грубую проверку корректности объекта класса
Reading
, прежде чем записать его в память.

const int implausible_min = –200;

const int implausible_max = 200;

bool is_valid(const Reading& r)

// грубая проверка

{

  if (r.day<1 || 31<r.day) return false;

  if (r.hour<0 || 23<r.hour) return false;

  if (r.temperature<implausible_min || 
implausible_max<r.temperature)

    return false;

  return true;

}

150
{"b":"847443","o":1}