Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции C++.doc
Скачиваний:
6
Добавлен:
01.05.2025
Размер:
1.44 Mб
Скачать

7.3.2 Перегрузка операторов извлечения

Для того, чтобы перегрузить оператор извлечения — экстрактор, используется тот же самый об­щий подход, что и для перегрузки операторов вставки — инсертеров. Например, следующий эк­страктор осуществляет ввод трехмерных координат. Обратим внимание, что он также осуществ­ляет подсказку пользователю.

// получение трехмерных координат – экстрактор

istream& operator>>(istream &stream, point &obj)

{

cout << "Enter x y z values, separating each with a space: ";

stream >> obj.x >> obj.y >> obj.z;

return stream;

}

Первым параметром должна быть ссылка на объект типа istream. Вторым параметром служит ссылка на объект, принимаю­щий ввод. Поскольку это именно ссылка, то второй аргумент может быть модифицирован при вводе информации. Экстрактор должен возвращать ссылку на объект типа istream.

Общая форма экстрактора имеет вид:

istream& operator>>(istream &поток, класс &объект)

{

// код экстрактора

return stream;

}

Следующая программа демонстрирует экстрактор для объекта класса point:

int main()

{

point a(1, 2, 3);

cout << a;

cin >> a; cout << a;

return 0;

}

Подобно функциям вставки, функции извлечения не могут быть членами класса, с элементами которого они оперируют. Как показано в примере, они могут быть друзьями или просто незави­симыми функциями. За исключением того, что экстрактор должен возвращать ссылку на объект типа istream, внутри экстрактора можно делать все, что угодно. Однако для лучшей структуриза­ции программы и ее ясности лучше всего ограничить эти действия только операциями ввода.

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

Как известно, с помощью функции printf() можно управлять форматированием информации, выводимой на экран. Например, можно указать ширину полей, левое или правое выравнивание и т.д. Все те же типы форматирования можно осуществить и в рамках ввода/вывода языка C++. Имеет­ся два способа форматирования вывода. Первый из них использует функции-члены класса ios. Второй использует специальный тип функции, называемой манипулятор. Начнем рассмотре­ние форматирования с использования функций-членов класса ios.

7.4.1 Форматирование с помощью функций-членов класса ios

В заголовочном файле ios.h определены следующие переменные перечисляемого типа:

enum

{

skipws = 0x0001, left = 0x0002, right = 0x0004, internal = 0x0008, dec = 0x0010, oct = 0x0020, hex = 0x0040, showbase = 0x0080, showpoint = 0x0100, uppercase = 0x0200, showpos = 0x0400, scientific = 0x0800, fixed = 0x1000, unitbuf = 0x2000, stdio = 0x4000, boolalpha = 0x8000

};

Определенные таким способом значения переменных перечисляемого типа используются для уста­новки или сброса флагов, управляющих форматированием информации потоков.

Когда установлен флаг skipws, то следующие в начале символы-разделители (пробелы, символы табуляции и новой строки) при выполнении ввода отбрасываются. Когда флаг skipws сброшен, символы-разделители сохраняются.

При установке флага left осуществляется вывод с левым выравниванием. Соответственно при установке флага right вывод осуществляется с правым выравниванием. По умолчанию вывод осуществляется с выравниванием по правому краю.

При установке флага internal поле, отведенное для вывода, заполняется пробелами до знака или буквы. Далее будет показано, как указать ширину поля.

Также по умолчанию численные значения выводятся в десятичной форме. Однако можно пере­определить такой способ. Например, установка флага oct задает вывод в восьме­ричной форме. Установка флага hex задает вывод в шестнадцатеричной форме. Для возвращения к десятичному выводу следует установить флаг dec.

Установка флага showbase позволяет при выводе указывать числовую базу (десятичную, восьме­ричную, шестнадцатеричную).

Установка флага showpoint приводит к выводу десятичной запятой и нулей справа для всех чисел с плавающей запятой вне зависимости, нужно это или нет.

По умолчанию при выводе научных данных, т.е. при использовании экспоненциальной формы записи чисел с плавающей запятой, используется 'е' в нижнем регистре. Также при выводе шест­надцатеричных величин символ 'x' выводится в нижнем регистре. При установке флага uppercase эти символы будут выводиться в верхнем регистре.

Установка флага showpos приводит к тому, что перед положительными числами будет выво­диться знак «плюс».

При установке флага scientific числа с плавающей запятой выводятся с использованием науч­ной нотации. При установке флага fixed числа с плавающей запятой выводятся в обычной нотации. По умолчанию, когда установлен флаг fixed, для десятичных цифр выводятся шесть позиций. Когда ни один из флагов не установлен, компилятор выбирает подходящий метод сам.

При установке флага unitbuf при каждой операции вставки данные немедленно заносятся в поток.

При установке флага stdio после каждого вывода данные заносятся в потоки stdout и stderr.

При установке флага boolalpha можно вводить и выводить данные булевого типа.

Флаги хранятся в формате длинных целых. В проекте стандарта ANSI для языка C++ этот тип обозначается как fmtflags, но в MS Visual C++ 7.0 флаги имеют тип long.

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

long setf(long flags);

Эта функция возвращает предыдущее значение флага и присваивает ему зна­чение параметра flags. При этом все остальные флаги остаются неизменными. Напри­мер, для того чтобы установить флаг showbase, можно использовать следующую инструкцию:

stream.setf(ios::showbase);

Здесь stream является каким-либо потоком, на который надо оказать воздействие. Например, следующая программа устанавливает флаги showpos и scientific для cout:

#include <iostream.h>

int main()

{

cout.setf(ios::showpos);

cout.setf(ios::scientific);

cout << 123 << " " << 123.23 << " ";

return 0;

}

Данная программа выводит на экран следующие данные:

+123 +1.232300е+02

С помощью операции побитового ИЛИ можно установить одновременно столько флагов, сколько надо. Например, можно изменить программу таким образом, что будет осуществляться только один вызов функции setf() при установке обоих флагов scientific и showpos:

cout.setf(ios::scientific || ios::showpos);

Для отключения флагов надо использовать функцию unsetf(). Она имеет следующий прототип:

long unsetf(long flags);

Функция возвращает значение состояния флага и сбрасывает флаги, определяемые параметром flags.

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

long flags() const;

Эта функция возвращает текущие значения флагов, ассоциированных с тем потоком, членом ко­торого она является. Используя следующую форму функции flags(), можно установить значения флагов на указанные в параметрах flags() и возвратить предыдущие значения флагов:

long flags(long new_flags);

Для того чтобы познакомиться с работой функций flags() и unsetf(), рассмотрим следующую программу. Она включает в себя функцию, называемую showflags(), которая выводит значения флагов.

#include <iostream.h>

void showflags(long f)

{

for(long i=0x8000; i; i = i >> 1)

if(i & f) cout << “1“;

else cout << "0";

cout << "\n";

}

int main()

{

long f = cout.flags();

showflags(f);

cout.setf(ios::showpos | ios::scientific);

f = cout.flags();

showflags(f);

cout.unsetf(ios::scientific);

f = cout.flags();

showflags(f);

return 0;

}

Исполнение данной программы выдаст следующие данные:

0000000000000001

0000110000000001

0000010000000001

Кроме флага форматирования также можно установить ширину поля потока, символ для за­полнения и число цифр после десятичной запятой. Для этого используются следующие функции:

int width(int len);

char fill(char ch);

int precision(int num);

Функция width() возвращает текущую ширину поля потока и устанавливает новое значение, опреде­ляемое параметром len. По умолчанию ширина поля изменяется в зависимости от числа симво­лов, необходимых для записи данных. Функция fill() возвращает текущее значение символа для заполнения, которым по умолчанию является пробел, и устанавливает текущий символ заполне­ния равным ch. Символ заполнения используется для заполнения пустых мест в соответствии с заданной спецификацией ширины поля. Функция precision() возвращает число цифр после деся­тичной запятой и устанавливает новое значение, задаваемое параметром пит. Ниже представлена программа, демонстрирующая использование этих трех функций:

#include <iostream.h>

int main()

{

cout.setf(ios::showpos | ios::scientific);

cout << 123 << " " << 123.23 << "\n";

cout.precision(2); // две цифры после запятой

cout.width(10); // поле из десяти символов

cout << 123 << " " << 123.23 << "\n";

cout.fill('#'); // заполнение символом #

cout.width(10); // поле из десяти символов

cout << 123 << " " << 123.23;

return 0;

}

Программа выдаст следующий результат:

+123 +1.232300е+02

+123 +1.23е+02

######+123 +1.23е+02

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