Краткая характеристика иерархии классов производных от conbuf.
Потоковые классы С++ Библиотека потоковых классов в С++ состоит из нескольких классов, распределенным по двум отдельным иерархическим деревьям.
Класс conbuf (constrea.h) Специализирует streambuf для обработки консольного вывода. Функции-элементы
Иерархия классов производных от ios На вершине иерархии находится класс ios, который, несмотря на то, что технически не является абстрактным, как правило, не используется для создания объектов ввода-вывода, а используется только в качестве базового класса для остальных потоков ввода-вывода. Действительно, класс ios содержит единст венный открытый конструктор потока, для использования которого требуется иметь предварительно созданный объект типа streambuf, обеспечивающий возможности буферизованного ввода или вывода. В большинстве случаев намного удобнее воспользоваться производными от ios классами, которые обеспечивают более простой интерфейс для создания потоковых объектов и предоставляют дополнительную функциональность, адаптированную к задачам ввода или вывода данных.
При работе с потоковой библиотекой ввода-вывода программист обычно достаточно активно использует следующие классы:
Состояния потока. Ошибки потоков. Состояние потока Каждый поток имеет связанное с ним состояние. Состояния потока описываются в классе ios в виде перечисления enum. public: enum io_state { goodbit, // нет ошибки 0Х00 eofbit, // конец файла 0Х01 failbit, // последняя операция не выполнилась 0Х02 badbit, // попытка использования недопустимой операции 0Х04 hardfail // фатальная ошибка 0Х08 };Флаги, определяющие результат последней операции объектом ios, содержатся в переменной state. Получить значение этой переменной можно с помощью функции int rdstate(). Кроме того, проверить состояние потока можно следующими функциями: int bad(void); // 1, badbit или hardfailint eof(void); // 1, если eofbitint fail(void); // 1, если failbit, badbit или hardfailint good(void); // 1, если goodbitЕсли операция >> используется для новых типов данных, то при её перегрузке необходимо предусмотреть соответствующие проверки. Пользователей библиотеки iostream, разумеется, интересует, находится ли поток в ошибочном состоянии. Например, если мы пишем int ival;cin >>ival;и вводим слово "Borges", то cin переводится в состояние ошибки после неудачной попытки присвоить строковый литерал целому числу. Если бы мы ввели число 1024, то чтение прошло бы успешно и поток остался бы в нормальном состоянии.
Чтобы выяснить, в каком состоянии находится поток, достаточно проверить его значение на истину: if (!cin) // операция чтения не прошла или встретился конец файлаДля чтения заранее неизвестного количества элементов мы обычно пишем цикл while: while (cin >> word) // операция чтения завершилась успешно...Условие в цикле while будет равно false, если достигнут конец файла или произошла ошибка при чтении. В большинстве случаев такой проверки потокового объекта достаточно. Однако при реализации оператора ввода для класса WordCount из раздела 20.5 нам понадобился более точный анализ состояния. У любого потока есть набор флагов, с помощью которых можно следить за состоянием потока. Имеются четыре предикатные функции-члена:
43. Форматирование в си++. Форматирующие функции-члены. Форматирующие функции – элементы, изменяющие флаги форматирования. Управление потоков с помощью манипулятора. Для управления форматированием ввода-вывода предусмотрены три вида средств: форматирующие функции, флаги и манипуляторы. Все эти средства являются членами класса ios и потому доступны для всех потоков. Форматирование Непосредственное применение операций ввода << и вывода >> к стандартным потокам cout, cin, cerr, clog для данных базовых типов приводит к использованию ''умалчиваемых'' форматов внешнего представления пересылаемых значений. Форматы представления выводимой информации и правила восприятия данных при вводе могут быть изменены программистом с помощью флагов форматирования. Эти флаги унаследованы всеми потоками из базового класса ios. Флаги форматирования реализованы в виде отдельных фиксированных битов и хранятся в protected компоненте класса long x_flags. Для доступа к ним имеются соответствующие public функции.
Кроме флагов форматирования используются следующие protected компонентные данные класса ios: int x_width - минимальная ширина поля вывода. int x_precision - точность представления вещественных чисел (количество цифр дробной части) при выводе; int x_fill - символ-заполнитель при выводе, пробел - по умолчанию. Для получения (установки) значений этих полей используются следующие компонентные функции: int width(void);int width(int);int precision(void);int precision(int);char fill(void);char fill(char);форматирующие функции-члены. Их всего три: width(), precision() и fill(). По умолчанию при выводе любого значения оно занимает столько позиций, сколько символов выводится. Функция width() позволяет задать минимальную ширину поля для вывода значения. При вводе она задает максимальное число читаемых символов. Если выводимое значение имеет меньше символов, чем заданная ширина поля, то оно дополняется символами-заполнителями до заданной ширины (по умолчанию - пробелами). Если же выводимое значение имеет больше символов, чем ширина отведенного ему поля, то поле будет расширено до нужного размера. Эта функция имеет следующие прототипы: int width(int wide); Функция с первым прототипом задает ширину поля wide, а возвращает предыдущее значение ширины поля. Функция со вторым прототипом возвращает текущее значение ширины поля. По умолчанию она равна нулю, то есть вывод не дополняется и не обрезается. В ряде компиляторов после выполнения каждой операции вывода значение ширины поля возвращается к значению, заданному по умолчанию. Функция precision() позволяет узнать или задать точность (число выводимых цифр после десятичной точки), с которой выводятся числа с плавающей точкой. По умолчанию числа с плавающей точкой выводятся с точностью, равной шести цифрам. Функция precision () имеет следующие прототипы:
int precision(int prec); Функция с первым прототипом устанавливает точность в prec и возвращает предыдущую точность. Функция со вторым прототипом возвращает текущую точность. Функция fill() позволяет прочесть или установить символ-заполнитель. Она имеет следующие прототипы: char fill(char type ch); Функция с первым прототипом устанавливает ch в качестве текущего символа-заполнителя и возвращает предыдущий символ-заполнитель. Функция со вторым прототипом возвращает текущий символ-заполнитель. По умолчанию в качестве символа-заполнителя используется пробел. С каждым потоком связан набор флагов, которые управляют форматированием потока. Они представляют собой битовые маски, которые определены в классе ios как данные перечисления. Манипуляторы Несмотря на гибкость и большие возможности управления форматами с помощью компонентных функций класса ios, их применение достаточно громоздко. Более простой способ изменения параметров и флагов форматирования обеспечивают манипуляторы. Манипуляторами называются специальные функции, позволяющие модифицировать работу потока. Особенность манипуляторов состоит в том, что их можно использовать в качестве правого операнда операции >> или <<. В качестве левого операнда, как обычно, используется поток (ссылка на поток), и именно на этот поток воздействует манипулятор. Манипуляторы указывают, например, ширину поля, точность при вычислении с плавающей точкой и т.п. Для обеспечения работы с манипуляторами в классах istream и ostream имеются следующие перегруженные функции operator. istream &operator >>(istream &(*_f)(istream &));ostream &operator <<(ostream &(*_f)(ostream &));При использовании манипуляторов следует включить заголовочный файл <iomanip.h>, в котором определены встроенные манипуляторы. Манипуляторы действуют на ввод-вывод в поток до внесения новых изменений. Флаги форматирования
setbase() устанавливает основание счисления к любому из четырех значений:
44. Шаблоны функций С++
Шаблоны, которые называют иногда родовыми или параметризоавнными типами, позволяют создавать (конструировать) семейства родственных функций и классов. Цель введения шаблонов функций - автоматизация создания функций, которые могут обрабатывать разнотипные данные. В отличие от механизма перегрузки, когда для каждого набора формальных параметров определяется своя функция, шаблон семейства функций определяется один раз, но это определение параметризуется. Параметризовать в шаблоне функций можно тип возвращаемого функцией значения и типы любых параметров, количество и порядок размещения которых должны быть фиксированы. Для параметризации используется список параметров шаблона. В определении шаблона семейства функций используется служебное слово template. Для параметризации используется список формальных параметров шаблона, который заключается в угловые скобки <>. Каждый формальный параметр шаблона обозначается служебным словом class, за которым следует имя параметра (идентификатор). Пример определения шаблона функций, вычисляющих абсолютные значения числовых величин разных типов: template <class type> type abs (type x) { return x > 0? x: -x;} Шаблон семейства фукций состоит из двух частей - заголовка шаблона: template <список_параметров_шаблона> В качестве еще одного примера рассмотрим шаблон семейства функций для обмена значений двух передаваемых им параметров. template <class T> void swap (T* x, T* y) { T z = *x; *x = *y; *y = x; } Здесь параметр T шаблона функций используется не только в заголовке для спецификации формальных параметров, но и в теле определения функции, где он задает тип вспомогательной переменной z. Шаблон семейства функций служит для автоматического формирования конкретных определений функций по тем вызовам, которые транслятор обнаруживает в теле программы. Например, если программист употребляет обращение abs(-10.3), то на основе приведенного ранее шаблона компилятор сформирует такое определение функции: double abs (double x) {return x > 0? x: -x;} Далее будет организовано выполнение именно этой функции и в точку вызова в качестве результата вернется числовое значение 10.3. Если в программе присутствует приведенный ранее шаблон семейства функций swap() long k = 4, d = 8, swap (&k, &d); то компилятор сформирует определение функции: void swap (long* x, long* y) { long x = *x; *x = *y; *y = x; } Затем будет выполнено обращение именно к этой функции и значения переменных k, d поменяются местами. Если в той же программе присутствуют операторы: double a = 2.44, b = 66.3; swap (&a, &b); то сформируется и выполнится функция void swap (double* x, double* y) { double x = *x; *x = *y; *y = x; }
По существу механизм шаблонов функций позволяет автоматизировать подготовку переопределений перегруженных функций. При использовании шаблонов уже нет необходимости готовить заранее все варианты функций с перегруженным именем. Компилятор автоматически, анализируя вызовы функций в тексте программы, формирует необходимые определения именно для таких типов параметров, которые использованы в обращениях. Дальнейшая обработка выполняется так же, как и для перегруженных функций Параметры шаблонов. Можно считать, что параметры шаблона являются его формальными параметрами, а типы тех параметров, которые используются в конкретных обращениях к функции, служат фактическими параметрами шаблона. Именно по ним выполняется параметрическая настройка и с учетом этих типов генерируется конкретный текст определения функции. Однако, говоря о шаблоне семейства функций, обычно употребляют термин <список параметров шаблона>, не добавляя определения <формальных>. Перечислим основные свойства параметров шаблона: Имена параметров шаблона должны быть уникальными во всем определении шаблона. Список параметров шаблона функции не может быть пустым, так как при этом теряется возможность параметризации и шаблон функций становится обычным определением конкретной функции. В списке параметров шаблона функций может быть несколько параметров. Каждый из них должен начинаться со служебного слова class. Например, допустим такой заголовок шаблона: template <class type1, class type2> Соответственно, неверен заголовок: template <class type1, type2, type3> Недопустимо использовать в заголовке шаблона параметры с одинаковыми именами, то есть ошибочен такой заголовок: template <class t, class t, class t> Имя параметра шаблона (в примерах - type1, type2) имеет в определяемой шаблоном функции все права имени типа, то есть с его помощью могут специализироваться формальные параметры, определяться тип возвращаемого функцией значения и типы любых объектов, локализованных в теле функции. Имя параметра шаблона видно во всем определении и скрывает другие использования того же идентификатора в области, глобальной по отношению к данному шаблону функций. Если внутри тела определяемой функции необходим доступ к внешним объектам с тем же именем, нужно применять операцию изменения области видимости.
45. Шаблоны классов С++. Определение шаблона класса. Явная реализация некоторых методов для специфических типов. Полное переопределение шаблона класса для работы с некоторым особым типом. Шаблоны и дружественные функции.
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|