Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Курс ПЯВУ 2 сем / Лекции 2 сем / Л№34.Потоковый ввод / Лекция № 32.Потоковый ввод вывод.odt
Скачиваний:
11
Добавлен:
17.04.2015
Размер:
153.09 Кб
Скачать

Манипулятор

На следующем шаге мы введем понятие манипулятора.

Несмотря на гибкость и большие возможности управления форматами с помощью компонентных функций класса ios, их применение достаточно громоздко. Более простой способ изменения параметров и флагов форматирования обеспечивают манипуляторы, к возможностям которых мы перейдем.

Манипуляторами называют специальные функции, позволяющие программисту изменять состояния и флаги потока. Особенность манипуляторов и их отличие от обычных функций состоит в том, что их имена (без параметров) и вызовы (с параметрами) можно использовать в качестве правого операнда для операции обмена (<< или >>). В качестве левого операнда в этом выражении, как обычно, используется поток (ссылка на поток), и именно на этот поток оказывает влияние манипулятор.

К примеру, напомним, что манипулятор hex позволяет устанавливать шестнадцатеричное основание счисления выводимых в поток cout числовых значений. Выполнив последовательность операторов:

cout << "\nДесятичное число: " << 15 << hex;

cout << "\nШестнадцатеричное представление: << 15;

получим на экране:

Десятичное число: 15

Шестнадцатеричное представление: 0xF

Как наглядно показывает результат, применение манипулятора hex изменило одно из свойств потока cout. Десятичная целая константа 15 воспринимается и выводится на экран в шестнадцатеричном виде.

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

cout << 15 << hex << 15 << oct << 15 << dec << 15;

в качестве результата получим:

150xF01715

Манипуляторы библиотеки классов ввода-вывода языка С++ делятся на две группы: манипуляторы с параметрами и манипуляторы без параметров.

Манипуляторы без параметров:

dec - при вводе и выводе устанавливает флаг десятичной системы счисления;

hex - при вводе и выводе устанавливает флаг шестнадцатеричной системы счисления;

oct - при вводе и выводе устанавливает флаг восьмеричной системы счисления;

ws - действует только при вводе и предусматривает извлечение из входного потока пробельных символов (пробел, знаки табуляции '\t' и '\v', символ перевода строки '\n', символ возврата каретки '\r', символ перевода страницы '\f');

endl - действует только при выводе, обеспечивает включение в выходной поток символа новой строки и сбрасывает буфер (выгружает содержимое) этого потока;

ends - действует только при выводе и обеспечивает включение в поток нулевого признака конца строки;

flush - действует только при выводе и очищает выходной поток, т.е. сбрасывает его буфер (выгружает содержимое буфера).

Обратите внимание, что не все перечисленные манипуляторы действуют как на входные, так и на выходные потоки. Манипулятор ws действует только при вводе; endl, ends, flush - только при выводе.

Манипуляторы dec, hex, oct, задающие основание системы счисления, изменяют состояние потока, и это изменение остается в силе до следующего явного изменения.

Манипулятор endl рекомендуется использовать при каждом выводе, который должен быть незамедлительно воспринят пользователем. Например, его использование просто необходимо в таком операторе:

cout << "Ждите! Идет набор статистики." << endl;

При отсутствии endl здесь нельзя гарантировать, что сообщение пользователю не останется в буфере потока cout до окончания набора статистики.

Рекомендуется с помощью манипулятора flush сбрасывать буфер входного потока при выводе на экран подсказки до последующего ввода информации:

cout << "Введите название файла: " << flush;

cin >> fileName; // Здесь fileName - символьный массив.

Манипуляторы с параметрами определены в файле iomanip.h. Перечислим их:

setbase(int n)

устанавливает основание (n) системы счисления. Значениями параметра n могут быть: 0, 8, 10 или 16. При использовании параметра 0 основание счисления при выводе выбирается десятичным. При вводе параметр 0 означает, что целые десятичные цифры из входного потока должны обрабатываться по правилам стандарта ANSI языка С;

resetiosflags(long L)

сбрасывает (очищает) отдельные флаги состояния потоков ввода и вывода на основе битового представления значения параметра L (сбрасывает флаги в соответствии с единичными битами);

setiosflags(long L)

устанавливает отдельные флаги состояния (форматные биты) потоков ввода-вывода на основе битового представления значения параметра L (устанавливаются флаги в соответствии с единичными битами параметра);

setfill(int n)

значение параметра n в дальнейшем используется в качестве кода символа-заполнителя, который помещается в незанятых позициях поля при вводе значения (компонент х_fill класса ios);

setprecision(int n)

определяет с помощью значения параметра n точность представления вещественных чисел, т.е. максимальное количество цифр дробной части числа при вводе и выводе (компонент x_precision класса ios);

setw(int n)

значение параметра n задает минимальную ширину поля вывода (компонент x_width класса ios).

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

Итак, для управления форматом вывода (включения в поток) класс ios имеет следующие компоненты:

компонент (атрибут) x_flags;

функции доступа к атрибуту x_flags: flags() и setf();

атрибуты управления форматом: x_width, x_precision, x_fill;

принадлежащие классу функции: width(), precision(), fill();

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

Ввод/вывод для типов, определенных пользователем.

При передачах данных базовых типов потоки cin, cout "знают", как выполнять преобразования значений разных типов. Напомним, что при перегрузке функций конкретная реализация выбирается в соответствии с сигнатурой, т.е. зависит от фактических параметров. Подобным образом в выражениях:

cin >> операнд

и

cout << операнд

каждому типу правого операнда соответствует свое правило преобразования данных. Эти правила заранее оформлены в виде процедур (функций) специального вида, называемых операциями-функциями. Определения этих функций находятся в библиотеке ввода-вывода, а прототипы размещены в заголовочном файле iostream.h.

Чтобы использовать операции обмена << и >> с данными производных типов, определяемых пользователем, необходимо расширить действие указанных операций, введя новые операции-функции. Каждая из операций обмена << и >> бинарная, причем левым операндом служит объект, связанный с потоком, а правый операнд должен иметь желаемый тип. Этот бинарный характер операций обмена отражает спецификация параметров соответствующих операций-функций. Первый параметр - ссылка на объект потокового класса (тип istream& либо ostream&), второй параметр - ссылка или объект желаемого типа. Тип возвращаемого значения должен быть ссылкой на тот поток, для которого предназначена операция. Таким образом, формат операции-функции для перегрузки операций таков:

ostream& operator << (ostream& out, новый_тип имя)

{

. . . // Любые операторы для параметра нового_типа.

out <<... // Вывод значений нового_типа.

return out; // Возврат ссылки на объект класса ostream.

}

Здесь новый_тип - тип, определенный пользователем. Таким образом, если определить структурный тип (класс):

struct point // Точка трехмерного евклидова пространства.

{

float x; // Декартовы координаты точки.

float у;

float z;

}

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

ostream& // Тип возвращаемого значения.

operator << (ostream& t, point d)

{ return t << "\nx = " << d.x << " у = " << d.y << " z = " << d.z; }

Отметим, что в теле функции с "названием" operator <<, операция << используется в первом бинарном выражении с объектом t типа ostream& в качестве левого операнда. Правыми операндами для каждой из операций << служат значения стандартных (базовых) типов - символьные строки и вещественные числа типа float. Результат операции:

t << "\nx = "

- ссылка на объект типа ostream. Эта ссылка используется в качестве левого операнда при выводе << d.х и т.д. Так как d - имя формального параметра структурного типа point, то для обращения к компонентам структуры (х, у, z) используются уточненные имена d.x, d.y, d.z. В результате выполнения всей цепочки операций вывода в теле операции-функции формируется ссылка на объект типа ostream, и именно это значение ссылки возвращает в точку вызова оператор return. Тем самым операция включения в поток <<, применяемая в вызывающей программе к операнду типа point, вернет ссылку на выходной поток. Таким образом, сохраняется возможность применения операции << несколько раз в одном выражении, как это разрешено для операндов базовых типов (т.е. допустимы цепочки вывода). Например, если, определив структуру point и введя для нее приведенную выше операцию-функцию operator << (), выполнить программу: