Читаем Программирование полностью

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

{

  if (r.day<1 || 31

  if (r.hour<0 || 23

  if (r.temperatureimplausible_max

    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 ys;

while(true) {

  Year y; // объект класса Year каждый раз очищается

  if (!(ifs>>y)) break;

  ys.push_back(y);

}

cout << " считано " << ys.size() << " записей по годам.\n";

for (int i = 0; i

Функцию print_year() мы оставляем в качестве упражнения. 

<p id="AutBody_Root191"><strong>10.11.3. Изменение представления</strong></p>

Для того чтобы оператор >> класса Month работал, необходимо предусмотреть способ для ввода символьных представлений месяца. Для симметрии мы описываем способ сравнения с помощью символьного представления. Было бы слишком утомительно писать инструкции if, подобные следующей:

if (s=="jan")

  m = 1;

else if (s=="feb")

  m = 2;

...

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже