Программирование. Принципы и практика использования C++ Исправленное издание, стр. 151
В заключение можем прочитать объекты класса
Year>>Year>>Monthistream& 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)Readingis>>mmMonthis>>mMonthВ качестве альтернативы можно было бы сделать так, чтобы функция
operator>>(istream& is, Month& m)mMonth 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. Изменение представления
Для того чтобы оператор
>>Monthifif (s=="jan") m = 1;else if (s=="feb") m = 2;...Это не просто утомительно; таким образом мы встраиваем названия месяцев в код. Было бы лучше занести их в таблицу, чтобы основная программа оставалась неизменной, даже если мы изменим символьное представление месяцев. Мы решили представить входную информацию в виде класса
vector<string>