На этом шаге мы рассмотрим использование классов строковых потоков данных.
Для строк определены следующие потоковые классы, которые являются аналогами соответствующих классов файловых потоков данных:
По аналогии с классами файловых потоков данных эти классы объединены в иерархию, изображенную на рисунке 1.
Рис.1. Иерархия классов строковых потоков данных
Эти классы определяются в заголовочном файле <sstream> следующим образом:
namespace std { template <class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> > class basic_istringstream; typedef basic_istringstream <char> istringstream; typedef basic_istringstream<wchar_t> wistringstream; template <class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> > class basic_ostringstream; typedef basic_ostringstream<char> ostringstream; typedef basic_ostringstream<wchar_t> wostringstream; template <class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> > class basic_stringstream; typedef basic_stringstream<char> stringstream; typedef basic_stringstream<wchar_t> wstringstream; template <class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> > class basic_filebuf; typedef basic_filebuf<char> stringbuf; typedef basic_filebuf<wchar_t> wstringbuf; }
Главная функция в интерфейсе строковых потоков данных, str(), используется для работы с потоковым буфером (таблица 1).
Функция | Описание |
---|---|
str() | Возвращает буфер в виде строки |
str(string) | Присваивает string содержимое буфера |
Пример использования строковых потоков данных:
//--------------------------------------------------------------------------- #include <vcl.h> #include <iostream> #include <sstream> #include <bitset> #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[]) { ostringstream os; // Десятичное и шестнадцатеричное значение os << ToRus("десятичное: ") << 15 << hex << ToRus(" шестнадцатеричное: ") << 15 << endl; cout << os.str() << endl; // Присоединение вещественного числа и битового поля bitset<15> b(5789); os << ToRus("вещественное: ") << 4.67 << ToRus(" битовое поле: ") << b << endl; // Перезапись восьмеричным числом os.seekp(0); os << ToRus("восьмеричное: ") << oct << 15; cout << os.str() << endl; getch(); return 0; } //---------------------------------------------------------------------------
Результат выполнения программы выглядит так:
Рис.2. Результат работы приложения
Сначала в os выводятся два числа, десятичное и шестнадцатеричное. Затем к ним присоединяется вещественное число и битовое поле (в двоичном виде). Функция seekp() перемещает позицию записи в начало потока данных, поэтому при следующем вызове оператора << данные записываются в начало строки с перезаписью существующего строкового потока данных. Тем не менее символы, которые не были перезаписаны, остаются действительными. Еслн вы хотите полностью удалить текущее содержимое потока данных, присвойте новое содержимое буфера функцией str():
strm.str("");
Первые строки, записанные в os, завершаются манипулятором endl. Это означает, что в конце вывода производится перевод строки. Поскольку за строкой в поток данных также выводится манипулятор endl, в результате будут записаны два символа новой строки подряд. Этим объясняется наличие пустых строк в выходных данных.
При работе со строковыми потоками данных программисты часто допускают распространенную ошибку - они забывает извлечь строку функцией str() и вместо этого выводят объект потока данных. С точки зрения компилятора это вполне разумно и возможно, поскольку существует преобразование к void*. В результате состояние потока данных выводится в виде адреса (смотри 471 шаг).
Одним из типичных применений строковых выходных потоков данных является определение операторов вывода для пользовательских типов.
Строковые входные потоки данных в основном используются для форматированного чтения из существующих строк. Например, часто бывает проще читать данные по строкам и затем анализнровать каждую строку в отдельнести. В следующем фрагменте из строки s читается целое число х, равное 3, и вещественное число f, равное 0.7:
int х; float f; std::string s = "3.7"; std::istringstream is(s); is >> x >> f;
При создании строковых потоков данных могут задаваться флаги режима открытия файла (смотри 495 шаг) и/или существующие строки. С флагами ios::app и ios::ate символы, записанные в строковый поток данных, присоединяются к существующей строке:
std::string s; . . . . std::ostringstream os (s, ios::out | ios || app); os << 77 << std::hex << 77;
Однако строка, возвращаемая функцией str(), представляет собой копию строки s с присоединенными значениями 77 в десятичном и шестнадцатеричном виде. Сама строка s остается неизменной.
На следующем шаге мы рассмотрим потоковые классы char*.