Шаг 4.
Предопределенный обмен данными со стандартными потоками

    На этом шаге мы рассмотрим особенности обмена данными со стандартными потоками.

    Рассмотрим процесс ввода данных с применением операции извлечения. Например, как нужно в программе воспринять последовательность -2.3е+1, набираемую на клавиатуре? Это символьная строка, которую нужно разместить в массиве типа char[ ], или экспоненциальное представление вещественного числа типа float, либо типа double? Набирая на клавиатуре последовательность цифр 1234, можно интерпретировать ее либо как целое число, либо как символьную строку, либо как значение вещественного числа. А как же правильно ее воспринять?

    В таких языках, как FORTRAN или С, программист с помощью специальных средств форматирования должен указать правила преобразования и формы представления вводимой и выводимой информации. В библиотеке потокового ввода-вывода С++ возможность форматирования передаваемых данных также существует, но дополнительно имеется и широко используется новый механизм автоматического распознавания типов вводимых и выводимых данных. Он работает подобно механизму перегрузки функций. Потоковые объекты cin, cout, cerr, clog построены таким образом, что ввод и вывод выполняются по-разному в зависимости от типов правого операнда операций вставки << и извлечения >>. В текстах программ мы уже неоднократно пользовались этим свойством объектов cin и cout. Оператор:

        cout <<  "\n1234 =  " << 1234;

выведет с новой строки последовательность символов 1234, а затем целое число со значением 1234. И никакой подсказки от программиста не требуется! На основе анализа типа выражения, помещенного справа от операции включения <<, в поток помещаются коды внешнего представления данных соответствующих типов.

    Подобная ситуация и при вводе данных. По существу, операция >> извлечения из потока не одна, а существуют три по-разному выполняемых операции:

    Все они при чтении по умолчанию игнорируют ведущие пробелы, но затем выполняются по-разному, в зависимости от типа правого операнда. Иллюстрируя сказанное, рассмотрим, как будет воспринята одна и та же последовательность символов, набираемая на клавиатуре, если справа от cin >> поместить разные типы данных, но все они будут соответствовать одному и тому же участку памяти:

//OOР4_1.СРР - "стандартная" перегрузка операций <<, >> для базовых типов.
#include <iostream.h>
void main()
{ union
  { long integer;
    char line[4] ;
    float  real; }  mix;
  cout <<"\n\nВведите целое число   (mix.integer):   "; 
  cin >> mix.integer;
  cout << "mix.integer="  << mix.integer; 
  cout << "\nmix.line="  << mix.line; 
  cout << "\nmix.real=" << mix. real; 
  cout << "\n\nВведите строку (mix.line): "; 
  cin >> mix.line;
  cout << "mix.integer = " << mix.integer; 
  cout << "\nmix.line = "  << mix.line; 
  cout << "\nmix.real = "  << mix.real; 
  cout << "\n\nВведите вещественное число (mix.real): ";
  cin >> mix.real;
  cout << "mix.integer = " << mix.integer; 
  cout << "\nmix.line =  " << mix.line; 
  cout << "\nmix.real = "  << mix.real;
}
Текст этой программы можно взять здесь.

    Результат выполнения программы:

    Введите целое  число   (mix.integer):   888  <Enter>
    mix.integer =  888
    mix.line = x
    mix.real = 1.244353e-42

    Введите строку   (mix.line):   888  <Enter>
    mix.integer =  3684408
    mix.line = 888
    mix.real =  5.162955e-39

    Введите вещественное число   (mix.real):   888  <Enter> 
    mix.integer = 1147011072 
    mix.line  = 
    mix.real  =  888

    В программе определено объединение mix, сопоставляющее один и тот же участок памяти длиной 4 байта с данными разных типов long, char [4], float. Элементы объединения mix.integer, mix.line, mix.real используются в качестве правых операндов операций извлечения из потока >> и включения в поток <<. В зависимости от типа операнда одна и та же последовательность символов, набираемая на клавиатуре (в примере это 888), воспринимается и заносится в память либо как char [4], либо как long, либо как float.

    При выводе в поток cout одно и то же внутреннее значение участка памяти, отведенное для объединения mix, воспринимается и отображается на экране по-разному в зависимости от типа правого операнда. В библиотеке ввода-вывода С++ для обеспечения указанных возможностей используется тот же самый механизм перегрузки. Объекты cout, cin с операциями <<, >> "знают", как выполнять ввод-вывод значений разных типов.

    Еще раз обратим внимание на результаты выполнения npoгpaммы. "Правильно" выводятся значения именно тех типов, которые введены. "Неправильные" значения других типов не всегда понятны. Например, после ввода mix.real строка mix.line почему-то оказалась пустой. По-видимому, в первом байте массива char line [4] находится код нуля. Объяснение "неправильных" результатов вывод требует рассмотрения внутренних представлений, которые различны на разных ЭВМ, для разных компиляторов и даже для разных исполнений программы.

    На следующем шаге мы перечислим особенности операций вставки и извлечения.




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