Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
КРАТКИЙ ОБЗОР С.doc
Скачиваний:
1
Добавлен:
26.10.2018
Размер:
2.11 Mб
Скачать

10.2 Вывод

Строгую типовую и единообразную работу как со встроенными, так и с пользовательскими типами можно обеспечить, если использовать единственное перегруженное имя функции для различных операций вывода. Например:       put(cerr,"x = "); // cerr - выходной поток ошибок       put(cerr,x);       put(cerr,'\n'); Тип аргумента определяет какую функцию надо вызывать в каждом случае. Такой подход применяется в нескольких языках, однако, это слишком длинная запись. За счет перегрузки операции << , чтобы она означала "вывести" ("put to"), можно получить более простую запись и разрешить программисту выводить в одном операторе последовательность объектов, например так:       cerr << "x = " << x << '\n'; Здесь cerr обозначает стандартный поток ошибок. Так, если х типа int со значением 123, то приведенный оператор выдаст       x = 123 и еще символ конца строки в стандартный поток ошибок. Аналогично, если х имеет пользовательский тип complex со значением (1,2.4), то указанный оператор выдаст       x = (1,2.4) в поток cerr. Такой подход легко использовать пока x такого типа, для которого определена операция <<, а пользователь может просто доопределить << для новых типов.       Мы использовали операцию вывода, чтобы избежать многословности, неизбежной, если применять функцию вывода. Но почему именно символ << ? Невозможно изобрести новую лексему (см. 7.2). Кандидатом для ввода и вывода была операция присваивания, но большинство людей предпочитает, чтобы операции ввода и вывода были различны. Более того, порядок выполнения операции = неподходящий, так cout=a=b означает cout=(a=b). Пробовали использовать операции < и >, но к ним так крепко привязано понятие "меньше чем" и "больше чем", что операции ввода-вывода с ними во всех практически случаях не поддавались прочтению.       Операции << и >> похоже не создают таких проблем. Они асиметричны, что позволяет приписывать им смысл "в" и "из". Они не относятся к числу наиболее часто используемых операций над встроенными типами, а приоритет << достаточно низкий, чтобы писать арифметические выражения в качестве операнда без скобок:       cout << "a*b+c=" << a*b+c << '\n'; Скобки нужны, если выражение содержит операции с более низким приоритетом:       cout << "a^b|c=" << (a^b|c) << '\n'; Операцию сдвига влево можно использовать в операции вывода, но, конечно, она должна быть в скобках:       cout << "a<<b=" << (a<<b) << '\n';

10.2.1 Вывод встроенных типов

      Для управления выводом встроенных типов определяется класс ostream с операцией << (вывести):       class ostream : public virtual ios {       // ...       public:       ostream& operator<<(const char*); //строки       ostream& operator<<(char);       ostream& operator<<(short i)       { return *this << int(i); }       ostream& operator<<(int);       ostream& operator<<(long);       ostream& operator<<(double);       ostream& operator<<(const void*); // указатели       // ...       }; Естественно, в классе ostream должен быть набор функций operator<<() для работы с беззнаковыми типами.       Функция operator<< возвращает ссылку на класс ostream, из которого она вызывалась, чтобы к ней можно было применить еще раз operator<<. Так, если х типа int, то       cerr << "x = " << x; понимается как       (cerr.operator<<("x = ")).operator<<(x); В частности, это означает, что если несколько объектов выводятся с помощью одного оператора вывода, то они будут выдаваться в естественном порядке: слева - направо.       Функция ostream::operator<<(int) выводит целые значения, а функция ostream::operator<<(char) - символьные. Поэтому функция       void val(char c)       {       cout << "int('"<< c <<"') = " << int(c) << '\n';       } печатает целые значения символов и с помощью программы       main()       {       val('A');       val('Z');       } будет напечатано       int('A') = 65       int('Z') = 90 Здесь предполагается кодировка символов ASCII, на вашей машине может быть иной результат. Обратите внимание, что символьная константа имеет тип char, поэтому cout<<'Z' напечатает букву Z, а вовсе не целое 90.       Функция ostream::operator<<(const void*) напечатает значение указателя в такой записи, которая более подходит для используемой системы адресации. Программа       main()       {       int i = 0;       int* p = new int(1);       cout << "local " << &i       << ", free store " << p << '\n';       }       выдаст на машине, используемой автором,       local 0x7fffead0, free store 0x500c Для других систем адресации могут быть иные соглашения об изображении значений указателей.       Обсуждение базового класса ios отложим до 10.4.1.