Программирование >>  Операторы преобразования типа 

1 ... 187 188 189 [ 190 ] 191 192 193 ... 239


Манипуляторы 587

ных. В табл. 13.8 перечислены основные манипуляторы, определенные в заголовочных файлах <istream> и <ostream>.

Таблица 13.8. Манипуляторы, определенные в заголовках <i5tream> и <05tream>

Манипулятор

Класс

Описание

flush

basic ostream

Принудителы1ый вывод выходного буфера на устройство

endl

basic ostream

Запись символа новой строки в буфер и принудительный вывод выходного буфера на устройство

ends

basic ostream

Запись символа завершения строки в буфер

basic istream

Чтение с игнорированием пропусков

Помимо перечисленных манипуляторов, существуют и другие, например, предназначенные для смены формата ввода-вывода. Они представлены на с. 589.

Принципы работы манипуляторов

Реализация манипуляторов основана на очень простом приеме, который не только упрощает управление потоками данных, но и наглядно демонстрирует мощь механизма перегрузки функций. Манипуляторы представляют собой обычные функции, передаваемые операторам ввода-вывода в аргументах. Оператор вызывает переданную функцию. Например, оператор вывода класса ostream перегружается примерно так:

ostreem ostream::operator ( ostream i*op)iostream)) I

Вызов функции, передаваемой в параметре, с аргументом-потоком return (*op)(*this):

Аргумент ор представляет собой указатель на функцию. Точнее говоря, это функция, которая получает и возвращает поток данных ostream (предполагается, что возвращается тот же объект ostream, который был получен при вызове). Если второй операнд оператора << является такой функцией, то при ее вызове в аргументе передается первый операнд оператора <<.

На первый взгляд описание кажется очень сложным, но в действительности все относительно просто. Следующий пример поможет лучше разобраться в происходящем. Манипулятор (то есть функция) endl() для объекта ostream реализуется примерно так:

std::ostream& std::endl (std::ostreani& strm) {

Запись признака конца строки strm.putCXn):

Конкретная реализация выглядит несколько сложнее, потому что ей приходится конструировать объект seЩry, а также потому, что она оформляется в виде птаблона.



Принудительный вывод выходного буфера strm.flushO:

Возвращение strm для организации целочечных вызовов return strm:

Манипулятор используется в выражениях вида

std::COUt Std::endl:

Для потока данных cout вызывается оператор <<, которому во втором операнде передается функция endl(). Реализация оператора << преобразует этот вызов в вызов переданной функции, которой в качестве аргумента передается объект потока данных:

std:;endl(std::cout)

Чтобы добиться эффекта вывода*- манипулятора, можно просто использовать это выражение. Более того, у функциональной записи есть свои преимущества - она не требует указания пространства имен:

endl(std;:cout)

Это возможно благодаря тому, что функции ищутся в том пространстве имен, в котором определены их аргументы (см. с. 33).

Поскольку потоковые классы оформлены в виде шаблонов, параметризованных по типу символов, настоящая реализация endl() выглядит примерно так:

tempiate<class charT. class tra1ts>

std; ;basic ostream<charT.tra1ts>&

std::endl (std::basic ostream<charT.tra1ts>& strm)

strm.put(strm.widen(\n));

strm.flushO;

return strm:

Функция widen() преобразует символ новой строки к кодировке, используемой в потоке данных. За подробностями обращайтесь к с. 601.

В стандартную библиотеку С++ также включены параметризованные манипуляторы (то есть манипуляторы, которым при вызове передаются аргументы). Принципы работы этих манипуляторов зависят от реализации; не существует стандартных правил определения пользовательских параметризованных манипуляторов.

Стандартные параметризованные манипуляторы определяются в заголовочном файле <iomanip>. Если вы собираетесь использовать их, в программу необходимо включить соответствующий файл:

#1nclude <1omanip>

Все стандартные параметризованные манипуляторы связаны с форматированием данных, поэтому они будут рассматриваться далее при описании средств форматирования.



Пользовательские манипуляторы

в программе можно определять нестандартные (пользовательские) манипуляторы. Все, что для этого нужно, - написать функцию наподобие приведенной ранее функции endl(). Например, следующая функция определяет манипулятор, который игнорирует все символы до конца строки:

io/ignore.hpp #1nclude <istredm> #1nclude <lirn1ts>

template <class charT. class tra1ts> Inline

std::basic istream<charT.tra1ts>&

ignoreHne (std: :basic istream<charT.tralts>& strm)

Пропуск символов до конца строки

strm.ignore(std::numeric lim1ts<int>::max().strm.w1den(\n)):

Возвращение strm для организации цепочечных вызовов return strm;

Манипулятор просто поручает работу функции ignore(), которая игнорирует все символы до конца строки (функция ignore() описана на с. 584). Применение манипулятора выглядит очень просто:

Пропустить символы до конца строки std;;с1п ignoreLine;

Многократный вывод манипулятора позволяет проигнорировать сразу несколько строк:

Пропустить две строки

std::Cln IgnoreLine ignoreLine;

Такая конструкция работает, поскольку вызов функции ignore(max, с) означает пропуск всех символов, пока не обнаружится символ с во входном потоке данных (или пока не будет прочитано максимальное количество символов, или пока не будет достигнут конец потока данных). Но этот символ также пропускается перед возвращенцем из функции.

Форматирование

Форматы ввода-вывода в наибольшей степени зависят от двух факторов. Первый и наиболее очевидный - форматные флаги, которые, в частности, определяют точность вывода чисел, символ-заполнитель и основание системы счисления. Другой фактор - настройка форматов под национальные стандарты.



1 ... 187 188 189 [ 190 ] 191 192 193 ... 239

© 2006 - 2025 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика