Стандартные потоки

 

Выполнение любой программы С++ начинаются с четырьмя предопределенными открытыми потоками, объявленными как объекты классов _withassign в iostream.h следующим образом:

extern istream_withassign cin; extern ostream_withassign cout; extern ostream_withassign cerr; extern ostream_withassign clog;

Их конструкторы вызываются всякий раз при включении iostream.h, но фактическая инициализация выполняется только один раз.

Все эти предопределенные стандартные потоки по умолчанию связаны с терминалом.

Четыре стандартных потока предназначены для:

cin - стандартного ввода; 
     cout - стандартного вывода; 
     cerr - стандартного вывода ошибок; 
     clog - полностью буферизованного вывода ошибок.

В табл. 5 приведено назначение классов потокового ввода-вывода.

Таблица 5
Назначение классов потокового ввода-вывода
 
ios Потоковый базовый класс
Потоковые классы ввода
istream Потоковый класс общего назначения для ввода, являющийся базовым классом для других потоков ввода
ifstream Потоковый класс для ввода из файла
istream with assign Потоковый класс ввода для cin
istrstream Потоковый класс для ввода строк
Потоковые классы вывода
ostream Потоковый класс общего назначения для вывода, являющийся базовым классом для других потоков вывода
ofstream Потоковый класс для вывода в файл
ostream_withassign Потоковый класс ввода для cout, cerr, and clog
ostrstream Потоковый класс для вывода строк
Потоковые классы ввода-вывода
iostream Потоковый класс общего назначения для ввода-вывода, являющийся базовым классом для других потоков ввода-вывода
fstream Потоковый класс для ввода-вывода в файл
sir stream Потоковый класс для ввода-вывода строк
stdiostream Класс для ввода-вывода в стандартные файлы ввода-вывода
Классы буферов для потоков
Streambuf Абстрактный базовый класс буфера потока
filebuf Класс буфера потока для дисковых файлов
s trs treambuf Класс буфера потока для строк
stdiobuf Класс буфера потока для стандартных файлов ввода-вывода

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

Потоки ввода-вывода C++ предоставляют некоторые преимущества по сравнению с функциями ввода-вывода библиотеки С.

Безопасность типов. Сравним вызов функций библиотеки С и использование стандартных потоков С++. Вызов функции printf() выглядит следующим образом:

#include < stdio.h > 
     . . . 
     int n = 12; 
     char name[ ] = "Вывод строки на экран\n"; 
     printf("%d %s", i, name);

Этот вызов приведет к следующей правильной печати:

 

12   Вывод строки на экран

Но если по невнимательности поменять местами аргументы для printf(), ошибка обнаружится только во время исполнения программы. Может произойти все что угодно - от странного вывода до краха системы. Этого не может случиться в случае использования стандартных потоков:

#include < iostream.h > 
     cout << i <<' ' << name << '\n';

Так как имеются перегруженные версии операции сдвига operator<< (), правая операция всегда будет выполнена. Функция cout<< i вызывает operator<< (int), a cout<< name вызывает operator<< (const char*). Следовательно, использование стандартных потоков является безопасным по типам данных.

Расширяемость для новых типов. Другим преимуществом стандартных потоков С++ является то, что определенные пользователем типы данных могут быть без труда в них встроены. Рассмотрим класс Data, данные которого необходимо печатать:

struct Data { 
     int x; char* y;};

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

ostream &operator<< (ostream & out, const Data & р){ 
     return out << p.x << ' ' << p.у; 
     } 
     После этого станет возможно осуществлять вывод: 
     #include < iostream.h > 
     struct Data {int x; char* y; 
     Data (int x, char* y){this->x = x; this->y = y;} 
     };

ostream &operator<< (ostream & out, const Data & p){ 
     return out << p.x <<' '<< p.y; 
     }

void main(){ 
     Data p(1, "Error"); 
     cout << p<< '\n'; 
     }