Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Срауструп CPP.doc
Скачиваний:
4
Добавлен:
05.11.2018
Размер:
4.95 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.