Программирование. Принципы и практика использования C++ Исправленное издание
Шрифт:
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;
}
В заключение можем прочитать объекты класса
Year
. Оператор >>
в классе Year
аналогичен оператору >>
в классе Month
.
istream& operator>>(istream& is, Year& y)
// считывает объект класса Year из потока is в объект y
// формат: { year 1972... }
{
char ch;
is >> ch;
if (ch!='{') {
is.unget;
is.clear(ios::failbit);
return is;
}
string year_marker;
int yy;
is >> year_marker >> yy;
if (!is || year_marker!="year")
error("Неправильное начало Year");
y.year = yy;
while(true) {
Month m; // каждый раз создаем новый объект m
if(!(is >> m)) break;
y.month[m.month] = m;
}
end_of_loop(is,'}',"Неправильный конец Year");
return is;
}
Можно было бы сказать, что этот оператор “удручающе аналогичен”, а не просто аналогичен, но здесь кроется важный нюанс. Посмотрите на цикл чтения. Ожидали ли вы чего-нибудь подобного следующему фрагменту?
Month m;
while (is >> m)
y.month[m.month] = m;
Возможно, да, поскольку именно так мы до сих пор записывали все циклы ввода. Именно этот фрагмент мы написали первым, и он является неправильным. Проблема заключается в том, что функция
operator>>(istream& is, Month& m)
не присваивает объекту m совершенно новое значение; она просто добавляет в него данные из объектов класса Reading
. Таким образом, повторяющаяся инструкция is>>m
добавляла бы данные в один и тот же объект m
. К сожалению, в этом случае каждый новый объект класса Month
содержал бы все показания всех предшествующих месяцев текущего года. Для того чтобы считывать данные с помощью инструкции is>>m
, нам нужен совершенно новый объект класса Month
. Проще всего поместить определение объекта m в цикл так, чтобы он инициализировался на каждой итерации.
Поделиться:
Популярные книги
Жребий некроманта 2
2. Жребий некроманта
Фантастика:
боевая фантастика
6.87
рейтинг книги
Предатель. Вернуть любимую
4. Измены
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Бывший муж
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Мама для дракончика или Жена к вылуплению
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Жандарм 5
5. Жандарм
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Менталист. Эмансипация
1. Выиграть у времени
Фантастика:
альтернативная история
7.52
рейтинг книги
Кодекс Охотника. Книга XXIV
24. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Лорд Системы 14
14. Лорд Системы
Фантастика:
фэнтези
попаданцы
рпг
5.00
рейтинг книги
Смерть может танцевать 4
4. Безликий
Фантастика:
боевая фантастика
5.85
рейтинг книги
Идеальный мир для Лекаря 2
2. Лекарь
Фантастика:
юмористическая фантастика
попаданцы
аниме
5.00
рейтинг книги
Черный Маг Императора 8
8. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Не отпускаю
Любовные романы:
современные любовные романы
эро литература
8.44
рейтинг книги
Идеальный мир для Лекаря 8
8. Лекарь
Фантастика:
юмористическое фэнтези
аниме
7.00
рейтинг книги
Темный Патриарх Светлого Рода 3
3. Темный Патриарх Светлого Рода
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00