Урок №209. Функционал классов ostream и ios. Форматирование вывода

  Юрий  | 

  Обновл. 14 Ноя 2019  | 

 4777

 ǀ   4 

В этом уроке мы рассмотрим функционал классов ostream и ios.

Примечание: Весь функционал объектов, которые работают с потоками ввода/вывода, находится в пространстве имён std. Это означает, что вам нужно либо добавлять префикс std:: ко всем объектам/функциям ввода/вывода, либо использовать в программе строчку using namespace std;.

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

Оператор вставки (вывода) << используется для помещения информации в выходной поток. А как мы уже знаем из урока о потоках, классы istream и ostream являются дочерними классу ios. Одной из задач iosios_base) является управление параметрами форматирования вывода.

Есть два способа управления параметрами форматирования вывода:

   флаги — это логические переменные, которые можно включать/выключать;

   манипуляторы — это объекты, которые помещаются в поток и влияют на способ ввода/вывода данных.

Для включения флага используйте функцию setf() с соответствующим флагом в качестве параметра. Например, по умолчанию C++ не выводит знак + перед положительными числами. Однако, используя флаг std::showpos, мы можем это изменить:

Результат:

+30

Также можно включить сразу несколько флагов, используя побитовый оператор ИЛИ (|):

Чтобы отключить флаг, используйте функцию unsetf():

Результат:

+30
31

Многие флаги принадлежат к определённым группам форматирования. Группа форматирования — это группа флагов, которые выполняют аналогичные (иногда взаимоисключающие) параметры форматирования вывода. Например, есть группа форматирования basefield.

Флаги группы форматирования basefield:

   octoctal» = «восьмеричный») — восьмеричная система счисления;

   decdecimal» = «десятичный») — десятичная система счисления;

   hexhexadecimal» = «шестнадцатеричный») — шестнадцатеричная система счисления.

Эти флаги управляют выводом целочисленных значений. По умолчанию установлен флаг std::dec, т.е. значения выводятся в десятичной системе счисления. Попробуем сделать следующее:

Результат:

30

Ничего не работает! Почему? Дело в том, что setf() только включает флаги, он не настолько умён, чтобы одновременно отключать другие (взаимоисключающие) флаги. Следовательно, когда мы включаем std::hex, std::dec также включен и у него приоритет выше. Есть два способа обойти эту проблему.

Во-первых, мы можем отключить std::dec, а затем включить std::hex:

Теперь уже результат тот, что нужно:

1e

Второй способ — использовать вариацию функции setf(), которая принимает два параметра:

   первый параметр — это флаг, который нужно включить/выключить;

   второй параметр — группа форматирования, к которой принадлежит флаг.

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

Результат:

1e

C++ также предоставляет ещё один способ изменения параметров форматирования: манипуляторы. Фишка манипуляторов в том, что они достаточно умны, чтобы одновременно включать и выключать соответствующие флаги. Например:

Результат:

1e
1f
32

В общем, использовать манипуляторы гораздо проще, нежели включать/выключать флаги. Многие параметры форматирования можно изменять как через флаги, так и через манипуляторы, но есть и такие параметры форматирования, которые изменить можно либо только через флаги, либо только через манипуляторы.

Полезные флаги, манипуляторы и методы


Ниже мы рассмотрим список наиболее полезных флагов, манипуляторов и методов. Флаги находятся в классе ios, манипуляторы — в пространстве имён std, а методы — в классе ostream.

Флаг:

   boolalpha — если включен, то логические значения выводятся как true/false. Если выключен, то логические значения выводятся как 0/1.

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

   boolalpha — логические значения выводятся как true/false.

   noboolalpha — логические значения выводятся как 0/1.

Например:

Результат:

1 0
true false
1 0
true false

Флаг:

   showpos — если включен, то к положительным числам прибавляется знак +.

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

   showpos — к положительным числам прибавляется знак +.

   noshowpos — к положительным числам не прибавляется знак +.

Например:

Результат:

7
+7
7
+7

Флаг:

   uppercase — если включен, то используются заглавные буквы.

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

   uppercase — используются заглавные буквы.

   nouppercase — используются строчные буквы.

Например:

Результат:

1.23457e+007
1.23457E+007
1.23457e+007
1.23457E+007

Флаги группы форматирования basefield:

   dec — значения выводятся в десятичной системе счисления;

   hex — значения выводятся в шестнадцатеричной системе счисления;

   oct — значения выводятся в восьмеричной системе счисления.

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

   dec — значения выводятся в десятичной системе счисления;

   hex — значения выводятся в шестнадцатеричной системе счисления;

   oct — значения выводятся в восьмеричной системе счисления.

Например:

Результат:

30
30
36
1e
30
36
1e

Теперь вы уже должны понимать связь между флагами и манипуляторами.

Точность, запись чисел и десятичная точка

Используя манипуляторы (или флаги), можно изменить точность и формат вывода значений типа с плавающей запятой.

Флаги группы форматирования floatfield:

   fixed — используется десятичная запись чисел типа с плавающей запятой;

   scientific — используется экспоненциальная запись чисел типа с плавающей запятой;

   showpoint — всегда отображается десятичная точка и конечные нули для чисел типа с плавающей запятой.

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

   fixed — используется десятичная запись значений;

   scientific — используется экспоненциальная запись значений;

   showpoint — отображается десятичная точка и конечные нули чисел типа с плавающей запятой;

   noshowpoint — не отображаются десятичная точка и конечные нули чисел типа с плавающей запятой;

   setprecision(int) — задаём точность для чисел типа с плавающей запятой.

Методы:

   precision() — возвращаем текущую точность для чисел типа с плавающей запятой;

   precision(int) — задаём точность для чисел типа с плавающей запятой.

Если используется десятичная или экспоненциальная запись чисел, то точность определяет количество цифр после запятой/точки. Обратите внимание, если точность меньше количества значащих цифр, то число будет округлено. Например:

Результат:

123.456
123.4560
123.45600
123.456000
123.4560000

1.235e+02
1.2346e+02
1.23456e+02
1.234560e+02
1.2345600e+02

Если не используются ни десятичная, ни экспоненциальная запись чисел, то точность определяет, сколько значащих цифр будет отображаться. Например:

Результат:

123
123.5
123.46
123.456
123.456

Используя манипулятор или флаг showpoint, мы можем заставить программу выводить десятичную точку и конечные нули. Например:

Результат:

123.
123.5
123.46
123.456
123.4560

Ширина поля, символы-заполнители и выравнивание


Обычно числа выводятся без учёта пространства вокруг них. Тем не менее, их можно выравнивать. Чтобы это сделать, нужно сначала определить ширину поля (т.е. количество пространства (пробелов) вокруг значений).

Флаги группы форматирования adjustfield:

   internal — знак значения выравнивается по левому краю, а само значение — по правому краю;

   left — значение и его знак выравниваются по левому краю;

   right — значение и его знак выравниваются по правому краю.

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

   internal — знак значения выравнивается по левому краю, а само значение — по правому краю;

   left — значение и его знак выравниваются по левому краю;

   right — значение и его знак выравниваются по правому краю;

   setfill(char) — задаём символ-заполнитель;

   setw(int) — задаём ширину поля.

Методы:

   fill() — возвращаем текущий символ-заполнитель;

   fill(char) — задаём новый символ-заполнитель;

   width() — возвращаем текущую ширину поля;

   width(int) — задаём ширину поля.

Чтобы использовать любой из объектов выше, нужно сначала установить ширину поля. Это делается с помощью метода width(int) или манипулятора setw(). Обратите внимание, по умолчанию при использовании ширины поля значения выравниваются по правому краю. Например:

Результат:

Теперь давайте зададим свой собственный символ-заполнитель:

Результат:

-12345
****-12345
-12345****
****-12345
-****12345

Обратите внимание, всё пустое пространство вокруг чисел заполнено * (символом-заполнителем).

Класс ostream и библиотека iostream содержат и другие полезные функции, флаги и манипуляторы. Но, как и в случае с классом istream, рассмотреть их все в рамках этого урока мы не можем. Однако основной функционал и общее представление вы получили.

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (20 оценок, среднее: 5,00 из 5)
Загрузка...

Комментариев: 4

  1. Аватар somebox:

    Рассказ про флаги заглавных букв иллюстрируется примером с цифрами. Интересно. 🙂 Только несчастный знак экспоненты "прыгает" туда-сюда.

  2. Аватар kmish:

    Еще такой момент. Если нам нужно несколько полей (столбцов) форматировать в строке, то std::setw необходимо дублировать.
    Например:

    Результат:

    -12345
    -12345
    -12345 345345
    -12345 345345
    - 12345-345345

  3. Евгений Евгений:

    Будете ли вы писать собственные или написанные другими для этого сайта уроки по C++? Просто это уже последняя глава, а как на этом сайте, как и на learncpp нет уроков по вариативным шаблонам, лямбда функциям и созданию своего потока ввода/вывода

    1. Юрий Юрий:

      Честно — не знаю. Сначала нужно эти уроки до конца довести.

Добавить комментарий

Ваш E-mail не будет опубликован. Обязательные поля помечены *