|
Программирование >> Разработка устойчивых систем
1os base basic ios<charT>
basic iostream<charT> В классе ios base объявляется все, что относится ко всем потокам независимо от типа символов. В основном это объявления констант и функций для работы с ними (примеры встретятся вам в этой главе). Остальные классы представляют собой шаблоны, параметризованные по типу символов. Например, класс Istream определяется следующим образом: typedef basic istream<char> istream: Все упоминавшиеся классы также представляют собой аналогичные определения типов. Кроме того существуют определения типов для всех потоковых классов, использующих тип wchar t (тип символов с расширенной кодировкой, о котором говорилось в главе 3) вместо char. Мы рассмотрим их в конце главы. Шаблон basicjos определяет функции, общие для ввода и вывода, но эти функции зависят от базового типа символов (в книге они встречаются редко). Шаблон basicjstream определяет общие функции ввода, а basic ostream делает то же самое для вывода. Классы файловых и строковых потоков определяют новые возможности для специализированных разновидностей потоков. В библиотеке потоков ввода-вывода были перегружены два оператора, упрощающие работу с потоками данных: оператор чтения из потока и оператор записи в поток . Оператор чтения из потока осуществляет разбор данных в соответствии с типом приемника. Для примера возьмем объект cin, потоковый аналог объекта stdin языка С, то есть перенаправляемый стандартный входной поток. Этот стандартный объект определяется при включении заголовочного файла <iostream>: int i: cin i: float f: cin f: char c: Cm. главу 5. Упомянутые потоковые классы в действительности представляют собой специализации шаблонов, по аналогии с тем, как стандартный класс string является специализацией шаблона basic string. Базовые классы иерархии потоков ввода-вывода изображены на следующем рисунке: cin с; char buf[100]: cin buf: Перегруженные версии оператора существуют для всех встроенных типов данных. Как будет показано далее, вы также можете перегружать его для своих типов. Вывод переменных осуществляется их записью в объект cout (аналог стандартного выходного потока; также существует объект cerr для стандартного потока ошибок) с помощью оператора : cout i = : cout i: cout \n : cout f = : cout f: cout \n : cout c = : cout c: cout \n : cout buf = : cout buf: cout \n : Такой синтаксис выглядит единообразно и не имеет особых преимуществ перед функцией printf(), несмотря на улучшенную проверку типов. К счастью, перегруженные операторы чтения и записи могут объединяться в более сложные выражения, которые гораздо удобнее читать (и записывать): cout i = i endl cout f = f endl cout c = с endl cout buf = buf endl: Определение операторов и для ваших классов сводится к простой перегрузке, которая должна делать следующее: первый параметр объявляется как неконстантная ссылка на поток данных (istream для ввода, ostream для вывода); операции выполняются записью-чтением соответствующих данных в поток или из него (по данным объекта); работа оператора завершается возвращением ссылки на поток. Поток должен быть неконстантным, потому что обработка потоковых данных изменяет состояние потока. Возвращение ссылки на поток позволяет объединять потоковые операции в одной команде, как показано выше. В качестве примера рассмотрим оператор для вывода представления объекта Date в формате ММ-ДД-ГГГГ: ostream& operator (ostream& os. const Date& d) { char fillc = os.fill(O): OS setw(2) d.getMonthO - setw(2) d.getDayO - setw(4) setfill(fillc) d.getYearO: return os: Эта операторная функция не может быть членом класса Date, потому что левый операнд оператора должен быть потоком вывода. Функция fill() класса ostream изменяет символ-заполнитель, используемый, если ширина поля, определяемая манипулятором setw(), превышает размер выводимых данных. Мы выбираем символ О , чтобы месяцы до октября отображались с начальным нулем (например, 09 для сентября). Функция fill() также возвращает предыдущий заполнитель (пробел по умолчанию), чтобы позднее его можно было восстановить манипулятором setfill(). Манипуляторы будут подробно описаны далее. С операторами чтения дело обстоит сложнее, потому что при чтении данных возможны ошибки. Сигналы об ошибках потоков подаются при помощи флага failbit, как показано в следующем примере: istreamS operator (istream& is, Date& d) { is d.month: char dash: is dash: if (dash != -) is.setstate(ios::failbit): is d.day: is dash: if (dash != -) is.setstate(ios::fail bit): Ts d.year: return is: Если установить для потока бит ошибки, все последующие операции с потоком игнорируются до тех пор, пока поток не будет восстановлен (об этом чуть позже). Именно поэтому оператор продолжает читать данные, не проверяя ios::failbit. Такая реализация допускает присутствие пропусков между числами и дефисами в строке даты (так как оператор по умолчанию игнорирует пропуски при чтении встроенных типов). Следующие строки являются допустимыми для данного оператора: 08-10-2003 8-10-2003 08 - 10 - 2003 А вот эти строки недопустимы: А-10-2003 Алфавитные символы запрещены 0810/2003 Разделителями могут быть только дефисы Состояние потока более подробно рассматривается в разделе Обработка потоковых ошибок этой главы. Типичное применение Как показывает оператор чтения для класса Date, следует учитывать возможность ошибок при вводе. Если прочитанные данные не соответствуют типу переменной, весь процесс нарушается, и восстановить нормальную работу программы будет нелегко. Кроме того, форматированный ввод по умолчанию разделяется пропусками. Посмотрим, что произойдет, если собрать приведенные выше фрагменты в программу: : C04:Iosexamp.cpp Пример работы с потоками ввода-вывода
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |