Г. Шилтд - Самоучитель C++ (PDF) (1114887), страница 38
Текст из файла (страница 38)
Для выполнения задания воспользуйтесь манипулятором setiosflagsQ3. Объясните, что дает установка флага boolalpha.8.5. Пользовательские функции выводаКак уже отмечалось в этой книге, одним из доводов в пользу использованияоператоров ввода/вывода C++, вместо аналогичных им функций ввода/вывода С, является возможность перегрузки операторов ввода/вывода длясоздаваемых вами классов. В этом разделе вы узнаете, как перегрузить оператор вывода «.В языке C++ вывод иногда называется вставкой (insertion), а оператор « —оператором вставки (insertion operator).
Когда вы для вывода информацииперегружаете оператор «, вы создаете функцию вставки (inserterfunction илиinserter). Рациональность этим терминам дает то, что оператор вывода вставляет (inserts) информацию в поток. Во избежание путаницы мы будем называть функцию вставки пользовательской функцией вывода.У всех пользовательских функций вывода следующая основная форма:ostream &operator« (ostream ustream, имя_класса объект;{//тело пользовательской функции выводаreturn stream,-iПервый параметр является ссылкой на объект типа ostream. Это означает,что поток stream должен быть потоком вывода. (Запомните, класс ostreamявляется производным от класса ios.) Второй параметр получает выводимыйобъект.
(Он, если для вашего приложения это нужно, тоже может быть параметром-ссылкой). Обратите внимание, что пользовательская функция вывода возвращает ссылку на поток stream, который имеет тип ostream. Этонеобходимо, если перегруженный оператор « должен использоваться в ряде последовательных выражений ввода/вывода:cout « оЫ « оЬ2 « оЬЗ;Внутри пользовательской функции вывода можно выполнить любую процедуру. То, что будет делать эта функция, полностью зависит от вас. Однако260Самоучитель С++в соответствии с хорошим стилем программирования, следует ограничитьзадачи пользовательской функции вывода только вставкой информации впоток.Хотя это на первый взгляд может показаться странным, но пользовательскаяфункция вывода не может быть членом класса, для работы с которым онасоздана.
И вот почему. Если оператор-функция любого типа является членом класса, то левый операнд, который неявно передается через указательthis, является объектом, генерирующим вызов оператор-функции. Это подразумевает, что левый операнд является объектом этого класса. Поэтому,если перегруженная оператор-функция является членом класса, тогда левыйоперанд должен быть объектом этого класса. Однако, когда вы создаетепользовательскую функцию вывода, левый операнд становится потоком, ане объектом класса, а правый операнд — объектом, который нужно вывести.Именно поэтому пользовательская функция вывода не может быть функцией-членом.То, что пользовательская функция вывода не может быть функцией-членомна первый взгляд кажется серьезным изъяном C++, поскольку подразумевает, что все данные класса, выводимые в поток через эту функцию, должныбыть открытыми, нарушая тем самым ключевой принцип инкапсуляции.Однако это не так. Несмотря на то, что пользовательские функции выводане могут быть членами класса, для работы с которым они разработаны, онимогут быть дружественными классу.
В подавляющем большинстве реальныхситуаций, с которыми вам придется столкнуться при программированииввода/вывода, перегружаемая пользовательская функция вывода будет дружественной классу, для которого она создана.Примеры1.^—^Для начала рассмотрим простой пример, в котором для класса coord, разработанного в предыдущей главе, создается пользовательская функция вывода:// Использование дружественной функции вывода// для объектов типа coord#include <iostream>using namespace std;class coord {int x, y;public:coordO ( x = 0; у = 0; }coord(int i, int j) { x = i; у = j; }friend ostream &operator«(ostream sstreara, coord obj;Глава 8. Введение в систему ввода/вывода C++261ostream &operator« (ostream Sstream, coord ob)pstream « ob.x « ", " « ob.y « ' \ n ;return stream;intmain()1coord a(l, 1) , b(10, 23) ;cout « a « b;return 0;В результате выполнения программы на экран выводится следующее:1, 110, 23Пользовательская функция вывода этой программы иллюстрирует одну оченьважную для создания ваших собственных функций особенность: их нужноразрабатывать, возможно, более обобщенными.
В данном конкретном случаеинструкция ввода/вывода внутри функции вставляет значения х и у в потокstream, который и является передаваемым в функцию потоком. Как вы увидите в следующей главе, та же самая пользовательская функция вывода, которая в нашем примере используется для вывода информации на экран,может использоваться и для ее вывода в любой поток. Тем не менее, начинающие программисты иногда пишут пользовательскую функцию вывода длякласса coord следующим образом:"ostream &operator«(ostream sstream, coord ob)'cout « ob.x « ", " « ob.y « ' \ n ' ;return stream;В этом случае выражение жестко запрограммировано на вывод информациина стандартное устройство вывода, связанное с классом cout.
Это ведет к тому, что другие потоки не могут воспользоваться вашей функцией. Выводочевиден, следует делать свои функции, возможно, более обобщенными, поскольку это никогда не повредит, а иногда может оказаться полезным.2. В следующей версии предыдущей программы, пользовательская функциявывода не является дружественной классу coord. Поскольку у пользовательской функции вывода нет доступа к закрытой части класса coord, переменные х и у приходиться делать открытыми.// Создание не дружественной функции вывода для объектов типа coord#include <iostream>using namespace std;_262СамоучительC++class coord {public:int x, у; // должны быть открытымиcoord{) { x = 0; у = 0; }coord (int i, int j) { x = i; у = j; }// Пользовательская функция вывода для объектов класса coordostream &operator« (ostream sstream, coord ob){stream « ob.x « ", " « ob.y « '\n';return stream;int main{){coord ail, 1) , b(10, 23) ;cout « a « b;return 0;3.Возможности пользовательских функций вывода не ограничиваются выводомтекстовой информации.
Они могут выполнить любое действие или преобразование, необходимое для вывода информации в том виде, который требуется из-за особенностей устройства или ситуации. Например, совершенноразумно создать пользовательскую функцию вывода для отправки информации на плоттер. В этом случае, кроме собственно информации, функция передаст предназначенные для управления плоттером коды. Чтобы вы моглипочувствовать вкус к такого рода функциям, в следующей программе создается класс triangle, в котором хранится ширина и высота прямоугольноготреугольника.
Пользовательская функция вывода этого класса выводит треугольник на экран.// Эта программа рисует прямоугольные треугольникиfinclude <iostream>using namespace std;class triangle {int height, base;public:triangle (int h, int b) { height = h; base= b; }friend ostream &operator« (ostream &stream, triangle ob) ;J;// рисование треугольникаostream soperator« (ostream sstream, triangle ob)iint i, j, h, k;Глава 8_._Введение а систему ввода/вывода C++263i = j = ob.base — 1;for(h=ob.height - 1; h; h —) {f o r ( k = i ; k; k —)stream « ' ';stream « ' * ' ;for(k=j - i - 1; k; k — )stream « ' ' ;stream « ' * ' ;i --;stream « ' \n' ;for(k=0; k <ob.base; k++) stream « '*•;stream « '\n' ;return stream;int mainf)triangle tl (5, 5 ) , t2 (10, 10), t3(12, 12)cout « tl;cout « endl « t2 « endl « t3;return 0;Отметьте, что должным образом разработанная пользовательская функциявывода может быть целиком вставлена в "обычное" выражение ввода/вывода.После выполнения программы на экран выводится следующее:***** ** ************* ****************************************************264Самоучитель С++_УпраЖнеж>>1.
В незавершенной программе имеется класс strtype. Для вывода строки наэкран создайте пользовательскую функцию вывода:ftinclude <iostream>^include <cstring>^include <cstdlib>using namespace std;class strtype {char *p;int len;public:strtype(char *ptr);-strtype () (delete [] p; }friend ostream &operator« (ostream &stream, strtype Sob);strtype;:strtype(char *ptr)len = strlen(ptr) + 1;p = new char [len];cout « "Ошибка выделения памяти\п";exit(l) ;.strcpy (p, ptr) ;// Здесь добавьте собственную функцию выводаint main ()strtype si ("Это проверка"), з2("Мне нравится C++");coat « si « '\n' « s2;return 0;2. Замените в следующей программе функцию show() пользовательской функцией вывода:^include <iostream>using namespace std;class planet {protected:double distance; // расстояние в милях от СолнцаГлава 8.
Введение в систему ввода/вывода C++265^int revolve;// полный оборот в дняхpublic:planet(double d, int r) { distance = d; revolve = r; )};class earth: public planet {double circumference; // окружность орбитыpublic:earth{double d, int r): planet(d, r) (circumference = 2 * distance * 3.1416;•/*Перепишите функцию show() так, чтобы информация выводилась спомощью пользовательской функции вывода*/void show () {cout « "Расстояние от Солнца: " « distance « '\п';cout « "Оборот вокруг Солнца: " « revolve « '\п';cout « "Окружность орбиты: " « circumference « '\п';};int main()earth ob(93000000, 365);cout « ob;return 0;3.
Вспомните, почему пользовательская функция вывода не может быть функцией-членом.8.6. Пользовательские функции вводаТочно так же, как мы перегружали оператор вывода «, можно перегрузитьи оператор ввода ». В C++ оператор ввода » иногда называют оператором извлечения (extraction operator), а функцию, перегружающую этот оператор, — функцией извлечения (extractor).
Смысл этих терминов в том, чтопри вводе информации мы извлекаем данные из потока. Во избежание путаницы мы будем называть функцию извлечения пользовательской функцией ввода.Здесь показана основная форма пользовательской функции ввода:istream Separator» (istream fistream, имя_класса &об-ъект)// тело пользовательской функции ввода266_СамоучительC++return stream;Пользовательские функции ввода возвращают ссылку на поток istream, который является потоком ввода.
Первый параметр тоже является ссылкой напоток ввода. Второй параметр — это ссылка на объект, получающий вводимую информацию.Так же, как и пользовательская функция вывода, пользовательская функцияввода не может быть функцией-членом. Хотя внутри такой функции можетбыть выполнена любая операция, лучше ограничить ее работу вводом информации.Примеры'Ъ*-1. В этой программе к классу coord добавлена пользовательская функция ввода:// Добавление дружественной функции ввода для объектов типа coord^include <iostream>using namespace std;class coord {int x, y;public:coord() { x = 0; у = 0; }coord(int i, int j) { x = i; у = j; }friend ostream soperator« (ostream Sstream, coord ob) ;friend istream separator»{istream Sstream, coord Sob);ostream &operator« (ostream sstream, coord ob)stream « ob.x « ", " « ob.y « '\n';return stream;istream ^operator» f istream sstream, coord &ob){cout « "Введите координаты: " ;stream » ob.x » ob.y;return stream;int main(){coord a(l, 1) , b(10, 23) ;cout « a « b;.Введениевсистемуввода/выводаC++_267cin » a;cout « a;return 0;Обратите внимание, как пользовательская функция ввода формирует строкуприглашение для ввода данных.