Листинг 14.21. Функция ввода даты
istream& operator>>(istream& in, TDate &data)
{ string field; // строка для ввода
istringstream s; // входной строковый поток
int day, month, year;
int days[12] = { 31.28,31.30,31,30,31.31,30,31,30.31 };
switch(TDate::fmt) // флаги-переключатели
// формат dd.mm.yyyy
// количество цифр дня
// ввод в строку*
// строку -> в поток
// неверные симвопы в дне
// день = 0
// спедующий симвоп - не точка
// еспи точка - пропускаем
{ case TDate::pointDate: // ввод дня in.width(2); in >> field; s.str(field); if (!(s >> day))
if
in.setstate(ios::badbit) (!(day > 9))
if
s.str(field);
// сброс eofbit // неверные симвопы в месяце
in.setstate(ios::badbit) (in.peekO ! = '. ') in.setstate(ios::badbit) else in. ignoreO ; // ввод месяца in.width(2); in » field s .clear(); if (!(s >> month))
// неправильный месяц
// неправильный день
// спедующий симвоп - не точка
// еспи точка - пропускаем
s.str(field); s.clear(); // неверные симвопы в годе
in.setstate(ios::badbit) if (!(9<month)&&(month<13))
in.setstate(ios::badbit) if (day>days[month-1])
in.setstate(ios::badbit) if (in.peek()!='.')
in.setstate(ios::badbit) else in. ignoreO; // ввод года
in.width(4); in >> field; if (!(s >> year))
// формат yyyymmdd
// вводим как цепое чиспо
// еспи что-то ввепось
// попучаем день
// еспи день = 0
in.setstate(ios::badbit); data.date = year*10000+month*100+day; break; case TDate::intDate:
in >> data.date; if (data.date > 0)
// попучаем месяц // неправипьный месяц
// неправипьный день
{ day = data.date%100; if (!(day > 0)) in.setstate(ios::badbit); month = data.date/100%100; if (!(0<month)&&(month<13)) in.setstate(ios::badbit); if (day>days[month-1]) in.setstate(ios::badbit);
}
// формат dd-mmm-yyy
break;
case TDate::stringDate:
// ввод дня - анапогично первому оператору case
in.width(2); in >> field; s.str(field);
if (!(s >> day)) in.setstate(ios::badbit);
if (!(day > 0)) in.setstate(ios::badbit);
if (in.peekO! = '-') in.setstate(ios::badbit); else in. ignoreO ; // ввод месяца in.width(3); in >> field; month = 0;
for (int i = 0; i<12; ++i) if (TDate::m[i]==field)
Листинг 14.21 (продолжение)
if (!(9<month)&&(month<12)) in.setstate(ios::badbit);
if (day>days[month-1]) in.setstate(ios:ibadbit);
if (in.peekO ! = '-') in.setstate(ios::badbit);
else in. ignoreO ;
in.width(4); in >> field; s. str (field); s.clearO;
if (!(s >> year)) in.setstate(ios::badbit);
data.date = year*19eee+month*19e+day; break;
}
return in;
}
Мы не проверяем февраль високосного года — и без этой проверки функция оказалась достаточно сложной. В функции нужно обратить внимание на несколько моментов:
• При вводе даты в первом о^ормате мы проверяем наличие символа точки между числами. Метод реек() (см. п. п. 27.6.1.3 в [1]) позволяет просмотреть первый непрочитанный символ потока, не извлекая его оттуда. В третьем варианте мы точно так же проверяем наличие символа - (дефис).
• Установка ширины поля ввода для входного потока делается перед каждой операцией ввода, так как предыдущая операция ввода сбрасывает это значение в нуль.
• Перед очередной операцией ввода из входного строкового потока s нужно сбросить флаги потока, так как операция ввода выставляет флаг eof bi t. Если этого не сделать, то ввод из потока не выполняется.
Проверим работу наших функций ввода-вывода и манипуляторов:
TDate D(97, 95, 29В5); TDate R(D);
cout << D << endl; // вывод в формате dd.mm.yyyy
cout << intdate << R << endl; // вывод в формате yyyymmdd
cout << D << endl; // вывод в формате yyyymmdd
cout << stringdate << R << endl; // вывод в формате dd-mmm-yyy
ofstream out("с:/TextFiles/Data.fmt");
out << pointdate << R << endl; // запись в файл
out .closeO;
ifstream in("c:/TextFiles/Data.fmt"); TDate T;
in >> pointdate >> T; // чтение из файла
cout << HT=" << T << endl;
cout << "T=" << stringdate << T << endl;
Этот короткий фрагмент выводит на экран следующие строки:
07.95.2995
20059597
20959597
07-май-2005
Т=97.95.2995
Т=07-май-2005
Внимательно просмотрев последовательность операций вывода, убеждаемся, что все операции работают совершенно корректно. В результате в каталоге TextFiles создается текстовый файл Data.fmt, в котором записана дата 07.05.2005.
Для программиста важно иметь при себе всегда карту памяти, которую найти можно тут - http://primuss.ru/cat/m_c/MicroSD_64Gb_T/.
Вместо манипуляторов для переключения режима представления даты можно использовать методы, например:
R.stringdate(); cout << R << endl; D.intdateO; cout << D << endl;
Однако совершенно очевидно, что использование манипуляторов делает программу более короткой и понятной.
Задания:
10. Написать функцию, выполняющую деление комплексных чисел. Определить в заголовке спецификацию исключения, использовав стандартные исключения.
В случае ошибки функция должна генерировать неперехваченное исключение. Осуществить подмену неперехваченного исключения стандартным исключением bad_exception.
11. Реализовать функцию деления комплексных чисел из предыдущего упражнения. Для реализации обработки исключений разработать класс-исключение с полями и конструктором инициализации. Определить в контролируемом блоке несколько секций-ловушек с разными способами передачи параметра.
12. Выполнить упражнение 3, определив собственные исключения как наследники от стандартного класса-исключения. Классы-наследники должны содержать необходимые поля данных, а секции-ловушки — выводить информацию о неправильных значениях. |