И наконец, заметьте, что встроенные типы, подобные int, читаются и записываются совершенно аналогично типам, определенным пользователями, таким, например, как Rational. Попробуйте сделать то же самое, используя scanf/printf!
Ниже приводится пример того, как можно написать функцию для вывода класса рациональных чисел:
class Rational
{
public:
Rational(int numerator=0, int denominator=1);
int n, d; //числитель и знаменатель
friend ostream& operator"(ostream& s, const Rational& r);
};
ostream& operator"(ostream& s, const Rational& r)
{
s " r.n " '/' " r.d;
return s;
}
Эта версия operator" демонстрирует некоторые тонкости (притом весьма важные!). Например, она не является функцией-членом, а объект Rational передается operator" по ссылке const, а не как объект. Соответствующая функция ввода, operator", объявляется и реализуется аналогичным образом.
Как ни обидно это признавать, в ряде случаев имеет смысл вернуться к старому и проверенному способу. Во-первых, некоторые реализации операций потоков ввода/вывода менее эффективны, чем соответствующие операции С, и возможно (хотя маловероятно), что в отдельных приложениях это может оказаться существенным. Помните, однако: это относится не к потокам ввода/вывода вообще, а только к той или иной реализации. Во-вторых, библиотека потоков ввода/вывода, в ходе своей стандартизации претерпела ряд кардинальных изменений. Следовательно, приложения, требующие максимальной переносимости, могут столкнуться с тем фактом, что различные поставщики поддерживают различные приближения стандарта.
И наконец, поскольку классы библиотеки потоков ввода/вывода имеют конструкторы, а функции <stdio.h> - нет, в редких случаях существенным будет порядок инициализации статических объектов, и стандартная библиотека С окажется более удобной просто потому, что вы можете ею пользоваться без опасений.
Контроль типов и расширяемость, предлагаемые классами и функциями библиотеки потоков ввода/вывода, являются более важными, чем это может показаться, - не стоит отвергать их только из-за того, что вы привыкли к <stdio.h>.
Между прочим, это не опечатка - в названии данного правила действительно фигурирует <iostream>, а не <iostream.h>. Строго говоря, такого заголовка, как <iostream.h>, не существует: Комитет по стандартам отказался от него в пользу названия <iostream> при сокращении имен стандартных файлов заголовков, отсутствующих в библиотеке языка С.
Важно уяснить следующее: если (что весьма вероятно) ваш компилятор поддерживает как файл заголовков <iostream>, так и <iostream.h>, необходимо иметь в виду, что они слегка отличаются друг от друга. В частности, если вы включаете <iostream>, элементы библиотеки потоков ввода/вывода весьма удобно расположены в пространстве имен std; включая <iostream.h>, вы получаете те же элементы, но в глобальном пространстве имен. Их определение в нем может вести к конфликтам, предотвращению которых и должно было послужить введение понятия пространства имен. Кроме того, <iostream> короче, чем <iostream.h>.
Для многих это оказывается достаточным аргументом в пользу нового названия. Вот на этом пока и все. Если будут вопросы - пишите. По результатам вашего любопытства могут появиться новые статьи.
При написании данного текста активно использовалась книга Скотта Мейерса.
Списоклитературы
Scott Meyers Effective C++ Second Edition AWG 1998