Шаг 503.
Библиотека STL.
Ввод-вывод с использованием потоковых классов. Классы строковых потоков данных

    На этом шаге мы рассмотрим использование классов строковых потоков данных.

    Для строк определены следующие потоковые классы, которые являются аналогами соответствующих классов файловых потоков данных:

    По аналогии с классами файловых потоков данных эти классы объединены в иерархию, изображенную на рисунке 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).

Таблица 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*.




Предыдущий шаг Содержание Следующий шаг