Потоки Язык C++ не обеспечивает средств для ввода/вывода Ему это и не нужно; такие средства легко и элегантно можно создать с помощью самого языка Традиционно средства ввода/вывода разрабатывались исключительно для небольшого числа встроенных типов данных. Например в Си: printf( " %d ", i); Однако в C++ обычно используется много типов, определенных пользователем
Обработка встроенных и определенных пользователем типов может достигаться с помощью одного перегруженных функций. Например: put(cerr,"x = "); // cerr - поток вывода ошибок Однако в С++ существует более элегантное решение
Библиотека потоков Библиотека потоков С++ предусматривает два основных класса для ввода и вывода: iostream и ostream Ввод и вывод осуществляется перегрузкой операций > "извлечение из потока" (класс istream) cerr
Приоритет
#include int main(void) { cout name; cout
Можно последовательно соединять несколько операций : #include int main(void) { char name[100]; cout > name; cout
Есть возможность переназначить потоки. Например: cout = cerr; В результате этого получаются две переменные, ссылающиеся на один и тот же поток. Главным образом это бывает полезно для того, чтобы сделать стандартное имя вроде cin ссылающимся на что-то другое
Предопределенные объекты-потоки Библиотека iostream имеет четыре предопределенных объекта- потока. Они ассоциированы со стандартным вводом/выводом ИмяТип класса cinistream_withassign Стандартный ввод (клавиатура) coutostream_withassign Стандартный вывод (экран) cerrostream_withassign Стандартное устройство ошибок (экран) c небуферизованным выводом clogostream_withassign Стандартное устройство ошибок (экран) c буферизованным выводом
Ввод/Вывод встроенных типов Класс ostream для вывода определяется вместе с операцией
Функция operator
Ввод аналогичен выводу. Имеется класс istream, который предоставляет операцию >> ("взять из") для небольшого множества стандартных типов. Функция operator>> может определяться для типа, определяемого пользователем. Класс istream для ввода определяется так: class istream { //... public: istream& operator>>(char*); // строка istream& operator>>(char&); // символ istream& operator>>(short&); i stream& operator>>(int&); istream& operator>>(long&); istream& operator>>(float&); istream& operator>>(double&); };
Функции ввода определяются в таком духе: istream& istream::operator>>(char& c) { // пропускает пропуски int a; // неким образом читает символ в "a" c = a; }
Ввод/Вывод типов, определяемых пользователем Рассмотрим определенный пользователем тип: class complex { double re, im; public: complex(double r = 0, double i = 0) { re=r; im=i; } friend double real(complex& a) { return a.re; } friend complex operator+(complex, complex); friend complex operator-(complex, complex); friend complex operator*(complex, complex); friend complex operator/(complex, complex); //... };
Операцию
Определение действия вывода для определяемого пользователем типа не требует ни модификации описания класса ostream, ни доступа к структуре данных (скрытой), которую этот класс поддерживает. Очень удачно, что имеет место первое, потому что описание класса ostream находится в стандартных заголовочных файлах, к которым у обычного пользователя нет доступа на запись. Последнее также важно, потому что обеспечивает защиту от случайной порчи структуры данных. Это также позволяет менять реализацию ostream не влияя на пользовательские программы.
Ввод для пользовательского типа может определяться точно так же, как вывод, за тем исключением, что для операции ввода важно, чтобы второй параметр был ссылочного типа: // форматы ввода для complex;"f" обозначает float: f ( f ) ( f, f ) istream& operator>>(istream& s, complex& a) { double re = 0, im = 0; char c = 0; s >> c; if (c == '(') { s >> re >> c; if (c == ',') s >> im >> c; if (c != ')') s.clear(_bad); // установить state } else { s.putback(c); s >> re; } if (s) a = complex(re,im); // OK return s; }
Несмотря на то, что не хватает кода обработки ошибок, большую часть видов ошибок это на самом деле обрабатывать будет. Локальная переменная c инициализируется, чтобы ее значение не оказалось случайно '(' после того, как операция окончится неудачно. Завершающая проверка состояния потока гарантирует, что значение параметра a будет изменяться только в том случае, если все идет хорошо. Операция установки состояния названа clear( ) (очистить), потому что она чаще всего используется для установки состояния потока заново как _good. является значением параметра по умолчанию и для istream::clear( ), и для ostream::clear( ).