На этом шаге мы рассмотрим возможность жесткого связывания потоков ввода-вывода.
Функция rdbuf() осуществляет жесткое связывание потоков данных с помощью общего потокового буфера (таблица 1).
Функция | Описание |
---|---|
rdbuf() | Возвращает указатель на потоковый буфер |
rdbuf(streambuf*) | Назначает потоковый буфер, определяемый аргументом, и возвращает указатель на предыдущий потоковый буфер |
Функция rdbuf() позволяет нескольким объектам потоков данных читать из одного входного канала или записывать в один выходной канал без нарушения порядка ввода-вывода. Однако использование нескольких потоковых буферов создает проблемы из-за буферизации операций ввода-вывода. Следовательно, применение для одного канала ввода-вывода разных потоков данных с разными буферами чревато ошибками при передаче данных. У классов baslc_istream и baslc_ostream имеются дополнительные конструкторы для инициализации потока данных с переданным в качестве аргумента буфером. Пример:
//--------------------------------------------------------------------------- #include <vcl.h> // Заголовочные файлы для файлового ввода-вывода #include <fstream> #include <iostream> #include <conio.h> //необходимо для getch() #pragma hdrstop //--------------------------------------------------------------------------- #pragma argsused using namespace std; std::string ToRus(const std::string &in) { char *buff = new char [in.length()+1]; CharToOem(in.c_str(),buff); std::string out(buff); delete [] buff; return out; } int main (int argc, char* argv[]) { // Поток для шестнадцатеричного стандартного вывода ostream hexout(cout.rdbuf()); hexout.setf (ios::hex, ios::basefield); hexout.setf (ios::showbase); // Переключение между десятичным и шестнадцатеричным выводом hexout << ToRus("Шестнадцатеричное: ") << 177 << endl; cout << ToRus("Десятичное: ") << 177 << endl; hexout << ToRus("Шестнадцатеричное: ") << -49 << endl; cout << ToRus("Десятичное: ") << -49 << endl; hexout << endl; getch(); return 0; } //---------------------------------------------------------------------------
Результат работы приложения выглядит так:
Рис.1. Результат работы приложения
Учтите, что деструктор классов basic_istream и basic_ostream не удаляет соответствующий потоковый буфер (который не открывается этими классами). Следовательно, чтобы передать поток данных при вызове, вместо ссылки на поток можно передать указатель на потоковый буфер:
//--------------------------------------------------------------------------- #include <vcl.h> // Заголовочные файлы для файлового ввода-вывода #include <fstream> #include <iostream> #include <conio.h> //необходимо для getch() #pragma hdrstop //--------------------------------------------------------------------------- #pragma argsused using namespace std; std::string ToRus(const std::string &in) { char *buff = new char [in.length()+1]; CharToOem(in.c_str(),buff); std::string out(buff); delete [] buff; return out; } void hexMultiplicationTable (std::streambuf* buffer, int num) { std::ostream hexout(buffer); hexout << std::hex << std::showbase; for (int i=1; i<=num; ++i) { for (int j=1; j<=10; ++j) { hexout << i*j << ' '; } hexout << std::endl; } } // НЕ ЗАКРЫВАЕТ буфер int main (int argc, char* argv[]) { using namespace std; int num = 5; cout << ToRus("Выводим ") << num << ToRus(" строк в шестнадцатеричном представлении") << endl; hexMultiplicationTable(cout.rdbuf(),num); cout << ToRus("Закончили вывод ") << num << ToRus(" строк в шестнадцатеричном представлении") << endl; getch(); return 0; } //---------------------------------------------------------------------------
Преимущество такого подхода заключается в том, что после модификации формат не нужно возвращать в исходное состояние, поскольку формат относится к объекту потока данных, а не к буферу. Результат работы приложения выглядит так:
Рис.2. Результат работы приложения
Впрочем, наряду с достоинствами имеется и недостаток - конструирование и уничтожение объекта потока данных обходится дороже, чем простая установка и восстановление форматных флагов. Также следует помнить, что уничтожение объекта потока данных не приводит к очистке буфера. Очищать выходной буфер необходимо "вручную".
Замечание о том, что потоковый буфер не уничтожается, относится только к классам basic_istream и basic_ostream. Другие потоковые классы уничтожают буферы, созданные ими же, но оставляют буферы, назначенные функцией rdbuf().
На следующем шаге мы рассмотрим перенаправление стандартных потоков данных.