Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Потоки ввода-вывода.doc
Скачиваний:
0
Добавлен:
14.11.2019
Размер:
338.94 Кб
Скачать

Потоки ввода-вывода

До сих пор в программных примерах мы пользовались только функциями стандартной библиотеки С. Однако в C++ имеются собственные средства, основанные на принципах классовой модели. Другими словами, в исполнительной библиотеке C++ имеется набор классов для управления вводом-выводом.

В отличие от функций буферизованного ввода-вывода С (таких, как print f и scanf, не выполняющих никаких проверок на соответствие аргументов форматной строке) классы потоков C++ безопасны в отношении типа. Ввод-вывод использует механизм перегрузки операций, гарантирующий вызов нужной функции-операции для указанного типа данных. Это главное преимущество потоков языка C++.

Классы потоков

К классам потоков относятся следующие:

  • Класс streambuf управляет буфером потока, обеспечивая базовые операции заполнения, опорожнения, сброса и прочих манипуляций с буфером.

  • Класс ios является базовым классом потоков ввода-вывода.

  • Классы istream и ostream — производные от ios и обеспечивают работу потоков соответственно ввода и вывода.

  • Класс iоstream является производным от двух предыдущих и предусматривает функции как для ввода, так и для вывода.

  • Классы ifstream, of stream и f stream предназначены для управления файловым вводом-выводом.

  • Классы istrstream и ostrstream управляют резидентными потоками (форматированием строк в памяти). Это устаревшая методика.

Для работы с потоками вам потребуется включить в программу заголовочный файл iostream.h. Кроме того, может потребоваться подключить файлы fstream.h (файловый ввод-вывод), iomanip.h (параметризованные манипуляторы) и strstream.h (форматирование ь памяти).

Предопределенные потоки

Библиотека ввода-вывода C++ предусматривает четыре предопределенных объекта-потока, связанных со стандартными входным и выходным устройствами. Ниже дана сводка этих объектов.

Таблица 1. Предопределенные объекты-потоки C++

Имя

Класс

Описание

Cin

istream

Ассоциируется со стандартным вводом (клавиатурой).

Cout

ostream

Ассоциируется со стандартным выводом (экраном).

cerr

ostream

Ассоциируется со стандартным устройством ошибок (экраном) без буферизации.

clog

ostream

Ассоциируется со стандартным устройством ошибок (экраном)с буферизацией.

 Операции извлечения и передачи в поток

Основными классами ввода-вывода C++ являются istream и ostream. Первый из них перегружает операцию правого сдвига (>>), которая служит в нем для ввода данных и называется операцией извлечения из потока. Класс ostream перегружает соответственно операцию левого сдвига (<<); она применяется для вывода и называется операцией передачи в поток.

Примечание

Нужно сказать, что стандартной русской терминологии как таковой в C++ не существует. Каждый изобретает свою собственную; иногда удачно, иногда — нет.

Вот простейшие операторы ввода и. вывода на стандартных потоках:

#include <iostream.h>

int main()

{

char name [ 8.0] ;

cout<< "Enter your name: ";

cin>> name;

cout <<"Hello " << name << "!";

return 0;

}

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

Перегруженные операции для встроенных типов

Классы istream и ostream перегружают операции соответственно извлечения и передачи в поток для всех встроенных типов. Это позволяет единообразно применять эти операции для чтения и вывода символов, целых, вещественных чисел (т. е. с плавающей точкой) и строк. Вот небольшая иллюстрация, где попутно показан еще простейший прием проверки на ошибку при вводе:

#include <iostream.h>

void check(void) {

if (!cin.good())

{

// Либо просто if (!cin) {

cout << "Error detected!";

exit (1);

}

int main(void)

{

double d;

long 1;

cout << "Enter a floating point value: ";

cin >> d;

check () ;

cout << "You entered: " << d << '\n';

cout << "Enter an integer value: ";

cin >> 1;

check () ;

cout << "You entered: " << 1 << '\n';

return 0;

}

Примечание

Операции извлечения и передачи в поток (соответственно для классов istream и ostream) можно перегрузить таким образом, чтобы можно было применять их для ввода или вывода объектов класса, определенного пользователем. Приведенный ниже пример демонстрирует эту методику. Вообще-то в подобных случаях совершенно необходимо предусмотреть детектирование и обработку ошибок ввода, но здесь мы этого не сделали.

#include <iostream.h>

class Point { int x, у;

public:

Point(int xx = 0, int yy = 0) {

x = xx; у = yy;

}

friend istream &operator>>(istream&, Points);

friend ostream &operator“(ostream&, Points);

};

istream &operator”(istream &is, Point &p)

//

// При вводе точка представляется просто парой чисел,

// разделенных пробелом.

// is >> р.х > р.у;

return is;

}

ostream &operator<<(ostream &os.Point &p) {

//

// Вывод в виде (х, у).

//

os<< ' ( '<< р. х<< ", "<< р. у<<') ' ;

return os;

}

int main() {

Point р;

cout<< "Enter point coordinates: ";

cin>> р;

cout<< "The point values are " << р;

return 0;

}

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

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

Форматирующие функции-элементы

Эти функции являются элементами класса ios и перегружены таким образом, чтобы можно было либо читать, либо устанавливать значение соответствующего атрибута потока. Если аргумент в вызове отсутствует, функция возвращает текущее значение атрибута. Если аргумент указан, функция устанавливает новое и возвращает предыдущее значение атрибута.

long width(long)

Эта функция предназначена для чтения или установки атрибута ширины поля.

  • Применяемая ко входному потоку, функция позволяет задать максимальное число вводимых символов.

  • На выходном потоке функция задает минимальную ширину поля вывода.

  • Если действительное поле вывода меньше установленной ширины, выводятся дополнительные заполняющие символы. Символ заполнения определяется специальным атрибутом потока.

  • Если действительное поле вывода больше установленной ширины, ее значение игнорируется.

  • Значением ширины по умолчанию является 0 (ширина поля определяется выводимыми данными).

  • Ширина поля сбрасывается в 0 после каждой передачи в поток.

char fill(char)

Функция позволяет прочитать или установить текущий символ заполнения.

По умолчанию символ заполнения — пробел.

long precision(long)

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

  • Точность по умолчанию равна шести цифрам.

  • Если установлен флаг scientific или fixed, точность задает число цифр после десятичной точки.

  • Если ни один из этих флагов не установлен, точность задает общее число значащих цифр.

Пример

Ниже приводится программа, демонстрирующая форматирование потока с помощью функций-элементов класса ios.

Листинг 1. Демонстрация форматирующих функций потока

///////////////////////////////////////////////

// Format.срр: Форматирующие функции-элементы ios.

//

#include <iostream.h>

#pragma hdrstop

#include <condefs.h>

#pragma argsused

int main(int argc, char* argv[])

{

//

// Ширина поля при вводе и выводе.

//

cnar sir [16];

cout<< "Enter something: ";

cin.width(16); // Ввод не более 15 символов. cin>> str;

cout.width(32); // Вывести в поле шириной 32. cout<< str<< "\n\n";

//

// Заполняющий символ и ширина поля. Ширина сбрасывается

// после каждой операции, поэтому она устанавливается

// для каждого числа.

//

int h = 7, m = 9, s = 0; // Выводятся в виде hh:mm:ss.

cout.fill('0'); cout << "Time is ";

cout.width (2); cout << h << ' : ' ; cout.width (2) ;

cout<< m<< ' : ' ;

cout.width (2) ;

cout<< s<< ".\n\n";

cout.fill (' '); // Восстановить пробел.

//

// Точность.

//

double d = 3.14159265358979;

float f = 27182.81828;

cout.precision (5);

cout << f << '\n'; . // Выводит "27183" .

cout << d << '\n'; ' // Выводит "3.1416".

cout .precision (4) ;

cout << f << '\n'; // Выводит "2.718е+04".

cout.setf(ios::fixed); // Установить флаг fixed.

cout<< f<<'\n'; // Выводит "27182.8184".

return 0;

}

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

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

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

Таблица 2. Простые и параметризованные манипуляторы

Манипулятор

Описание

dec

Задает десятичную базу преобразования.

end1

Передает в поток символ новой строки и сбрасывает поток.

ends

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

flush

Сбрасывает выходной поток.

hex

Задает шестнадцатеричную базу преобразования.

lock(ios Sir)

Блокирует дескриптор файла потока ir.

oct

Задает восьмеричную базу преобразования.

resetiosflags(int f)

Сбрасывает флаги, биты которых установлены в f.

setbase(int b)

Устанавливает базу преобразования (0, 8, 10 или 16).

setiosflags(int f)

Устанавливает флаги, биты которых установлены в f.

setfill(int c)

Задает символ заполнения (аналогичен функции fiilO).

setprecision(long p)

Задает точность (аналогичен функции precision ()).

setw(iong w)

Задает ширину поля (аналогичен функции width ()).

lunlock(ios &ir)

Разблокирует дескриптор файла для потока ir.

ws

Исключает начальные пробельные символы.

 

Вот пример использования некоторых манипуляторов (мы создали один свой собственный):