Шрифт:
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 в цикл так, чтобы он инициализировался на каждой итерации. В качестве альтернативы можно было бы сделать так, чтобы функция
operator>>(istream& is, Month& m)
перед считыванием в цикле присваивала бы объекту m
пустой объект.
Month m;
while (is >> m) {
y.month[m.month] = m;
m = Month; // "Повторная инициализация" объекта m
}
Попробуем применить это.
// открываем файл для ввода:
cout << "Пожалуйста, введите имя файла для ввода \n";
string name;
cin >> name;
ifstream ifs(name.c_str);
if (!ifs) error(" невозможно открыть файл для ввода ",name);
ifs.exceptions(ifs.exceptions|ios_base::badbit); // генерируем bad
// открываем файл для вывода:
cout << "Пожалуйста, введите имя файла для ввода \n";
cin >> name;
ofstream ofs(name.c_str);
if (!ofs) error(" невозможно открыть файл для ввода ",name);
// считываем произвольное количество объектов класса Year:
vector<Year> ys;
while(true) {
Year y; // объект класса Year каждый раз очищается
if (!(ifs>>y)) break;
ys.push_back(y);
}
cout << " считано " << ys.size << " записей по годам.\n";
for (int i = 0; i<ys.size; ++i) print_year(ofs,ys[i]);
Функцию
print_year
мы оставляем в качестве упражнения. 10.11.3. Изменение представления
Для того чтобы оператор
>>
класса Month
работал, необходимо предусмотреть способ для ввода символьных представлений месяца. Для симметрии мы описываем способ сравнения с помощью символьного представления. Было бы слишком утомительно писать инструкции if
, подобные следующей: