WWW.DISSERS.RU

БЕСПЛАТНАЯ ЭЛЕКТРОННАЯ БИБЛИОТЕКА

   Добро пожаловать!


Pages:     | 1 |   ...   | 13 | 14 || 16 | 17 |

12 Вывод строки на экран Но если по невнимательности поменять местами аргументы для printf(), ошибка обнаружится только во время исполнения программы.

Может произойти все что угодно – от странного вывода до краха системы. Этого не может случиться в случае использования стандартных потоков:

#include cout << i <<‘ ‘ << name << ‘\n’;

Так как имеются перегруженные версии операции сдвига operator<<(), правая операция всегда будет выполнена. Функция cout<

Следовательно, использование стандартных потоков является безопасным по типам данных.

Расширяемость для новых типов. Другим преимуществом стандартных потоков С++ является то, что определенные пользователем типы данных могут быть без труда в них встроены. Рассмотрим класс Data, данные которого необходимо печатать:

struct Data { int x; char* y;};

Все, что нужно сделать, это перегрузить операцию << для нового типа Data. Соответствующая функция operator<<() может быть реализована так:

ostream &operator<<(ostream & out, const Data & р){ return out << p.x << ‘ ‘ << p.у;

} После этого станет возможно осуществлять вывод:

#include struct Data {int x; char* y;

Data (int x, char* y){this->x = x; this->y = y;} };

ostream &operator<<(ostream & out, const Data & p){ return out << p.x <<‘ ‘<< p.y;

} void main(){ Data p(1, “Error“);

cout << p<<’\n’;

} 27.3. Операции помещения и извлечения из потока В ы в о д в п о т о к выполняется с помощью операции вставки (в поток), которая является перегруженной операцией сдвига влево <<.

Левым ее операндом является объект потока вывода. Правым операндом может являться любая переменная, для которой определен вывод в поток (то есть переменная любого встроенного типа или любого определенного пользователем типа, для которого она перегружена). Например, оператор cout << “Hello!\n“; приводит к выводу в предопределенный поток cout строки “Hello!“.

Операция << возвращает ссылку на объект типа ostream, для которого она вызвана. Это позволяет строить цепочки вызовов операции вставки в поток, которые выполняются слева направо:

int i = 5;

double d = 2.08;

cout << ”i = ” << i << ”, d = ” << d << ‘\n’;

Эти операторы приведут к выводу на экран следующей строки:

i = 5, d = 2.Операция вставки в поток поддерживает следующие встроенные типы данных: char, short, int, long, char* (рассматриваемый как строка), float, double, long double, void*:

ostream& operator<<(short n);

ostream& operator<<(unsigned short n);

ostream& operator<<(int n);

ostream& operator<<(unsigned int n);

ostream& operator<<(long n);

ostream& operator<<(unsigned long n) ;

ostream& operator<<(float f);

ostream& operator<<(double f);

ostream& opera to r<<(long double f) ;

ostream& operator<<(const void *p);

Целочисленные типы форматируются в соответствии с правилами, принятыми по умолчанию, если они не изменены путем установки различных флагов форматирования. Тип void* используется для отображения адреса:

int i;

// Отобразить адрес в 16-ричной форме:

cout << &i;

Отметим, что перегрузка не изменяет нормального приоритета выполнения операции <<, поэтому можно записать cout << “sum =“ << x+y << “\n“;

без круглых скобок. Однако, в случае cout << (x & y) << “\n“;

круглые скобки нужны.

Д л я в в о д а информации из потока используется операция извлечения, которой является перегруженная операция сдвига вправо >>.

Левым операндом операции >> является объект класса istream, который также является и результатом операции. Это позволяет строить цепочки операций извлечения из потока, выполняемых слева направо. Правым операндом может быть любой тип данных, для которого определен поток ввода.

istream& operator>>(short& n);

istream& operator>>(unsigned short& n);

istream& operator>>(int& n);

istream& operator>>(unsigned int& n);

istream& operator>>(long& n);

istream& operator>>(unsigned long& n);

istream& operator>>(float& f);

istream& operator>>(double& f);

istreaai& operator>>(long double& f);

istream& operator>>(void*& p);

По умолчанию операция >> пропускает символы-заполнители (по умолчанию – пробельные символы), затем считывает символы, соответствующие типу заданной переменной. Пропуск ведущих символов-заполнителей устанавливается специально для этого предназначенным флагом форматирования. Рассмотрим следующий пример:

int i;

double d;

cin >> i >> d;

Последний оператор приводит к тому, что программа пропускает ведущие символы-заполнители и считывает целое число в переменную i. Затем она игнорирует любые символы-заполнители, следующие за целым числом, и считывает переменную с плавающей точкой d.

Для переменной типа char* (рассматриваемой как строка) оператор >> пропускает символы-заполнители и сохраняет следующие за ними символы, пока не появится следующий символ-заполнитель. Затем в указанную переменную добавляется нуль-символ ‘\n’.

27.4. Форматирование потока Для управления форматированием ввода-вывода предусмотрены три вида средств: форматирующие функции, флаги и манипуляторы.

Все эти средства являются членами класса ios и потому доступны для всех потоков.

Рассмотрим вначале форматирующие функции-члены. Их всего три: width(), precision() и fill().

По умолчанию при выводе любого значения оно занимает столько позиций, сколько символов выводится. Функция width() позволяет задать минимальную ширину поля для вывода значения. При вводе она задает максимальное число читаемых символов. Если выводимое значение имеет меньше символов, чем заданная ширина поля, то оно дополняется символами-заполнителями до заданной ширины (по умолчанию – пробелами). Если же выводимое значение имеет больше символов, чем ширина отведенного ему поля, то поле будет расширено до нужного размера. Эта функция имеет следующие прототипы:



int width(int wide);

int width() const;

Функция с первым прототипом задает ширину поля wide, а возвращает предыдущее значение ширины поля. Функция со вторым прототипом возвращает текущее значение ширины поля. По умолчанию она равна нулю, то есть вывод не дополняется и не обрезается. В ряде компиляторов после выполнения каждой операции вывода значение ширины поля возвращается к значению, заданному по умолчанию.

Функция precision() позволяет узнать или задать точность (число выводимых цифр после десятичной точки), с которой выводятся числа с плавающей точкой. По умолчанию числа с плавающей точкой выводятся с точностью, равной шести цифрам. Функция precision () имеет следующие прототипы:

int precision(int prec);

int precision() const;

Функция с первым прототипом устанавливает точность в prec и возвращает предыдущую точность. Функция со вторым прототипом возвращает текущую точность.

Функция fill() позволяет прочесть или установить символзаполнитель. Она имеет следующие прототипы:

char fill(char type ch);

char fill() const;

Функция с первым прототипом устанавливает ch в качестве текущего символа-заполнителя и возвращает предыдущий символзаполнитель. Функция со вторым прототипом возвращает текущий символ-заполнитель. По умолчанию в качестве символа-заполнителя используется пробел.

Рассмотрим пример программы, в котором используются форматирующие функции:

void main() { double x;

cout.precision(4);

cout.fill(‘0’);

cout << ” x sqrt(x) x^2\n\n”;

for (x=1.0; x< 6.5; x++) { cout.width(7);

cout << x << ” ”;

cout.width(7);

cout << sqrt(x) << ” ”;

cout.width(7);

cout << x*x << ‘\n’;

} } Эта программа выводит на экран небольшую таблицу значений переменной x, ее квадратного корня и квадрата:

x sqrt(x) х^0000001 0000001 0000002 01.4142 0000003 01.7321 0000004 0000002 0000005 02.2361 0000006 02.4495 С каждым потоком связан набор флагов, которые управляют форматированием потока. Они представляют собой битовые маски, которые определены в классе ios как данные перечисления.

Флаги форматирования и их назначение приведены в табл. 6.

Таблица Флаги форматирования и их назначение Флаг Назначение hex Значения целого типа преобразуются к основанию (как шестнадцатеричные) dec Значения целого типа преобразуются к основанию oct Значения целого типа преобразуются к основанию (как восьмеричные) fixed Числа с плавающей точкой выводятся в формате с фиксированной точкой (то есть nnn.ddd) scientific Числа с плавающей точкой выводятся в так называемой научной записи (то есть n.хххЕуу) showbase Выводится основание системы счисления в виде префикса к целому числовому значению (например, число 1FE выводится как 0x1FE) showpos При выводе положительных числовых значений выводится знак плюс upper Заменяет определенные символы нижнего регистра на символы case верхнего регистра (символ ”е” при выводе чисел в научной нотации на ”Е” и символ ”х” при выводе 16-ричных чисел на ”X”) left Данные при выводе выравниваются по левому краю поля right Данные при выводе выравниваются по правому краю поля internal Добавляются символы-заполнители между всеми цифрами и знаками числа для заполнения поля вывода skipws Ведущие символы-заполнители (знаки пробела, табуляции и перевода на новую строку) отбрасываются stdio Потоки stdout, stderr очищаются после каждой операции вставки unitbuf Очищаются все выходные потоки после каждой операции вставки в поток stdio Очищаются stdout, stderr после каждой операции вставки в поток Флаги left и right взаимно исключают друг друга. Флаги dec, oct и hex также взаимно исключают друг друга.

Прочесть текущие установки флагов позволяет функция-член flags() класса ios. Для этого используется следующий прототип этой функции:

long flags();

Функция flags() имеет и вторую форму, которая может использоваться для установки значений флагов. Для этого используется следующий прототип этой функции:

long flags(long fmtfl);

В этом случае битовый шаблон копирует fmtfl в переменную, предназначенную для хранения флагов форматирования. Функция возвращает предыдущие значения флагов. Поскольку эта форма функции меняет весь набор флагов, она применяется редко. Вместо нее используется функция-член setf() класса ios, которая позволяет установить значение одного или нескольких флагов. Она имеет следующие прототипы:

long setf (long mask);

long setf (long fmtfl, long mask);

Первая функция-член неявно вызывает функцию flags (mask | flags()) для установки битов, указанных параметром mask, и возвращает предыдущие значения флагов. Второй вариант функции присваивает битам, указанным параметром mask, значения битов параметра fmtfl, а затем возвращает предыдущие значения флагов.

Например, следующий вызов функции setf() устанавливает для потока cout флаги hex и uppercase:

cout.setf(ios::hex | ios::uppercase);

В качестве второго параметра функции setf() можно использовать следующие константы, определенные в классе ios:





static const long basefield; // = dec | oct | hex static const long adjustfield; // = left | right | internal static const long floatfield; // = scientific | fixed Сбросить установленные флаги можно с помощью функции-члена unsetf() класса ios, имеющей следующий прототип:

void unsetf(long mask);

Она сбрасывает флаги, заданные параметром mask. Следующий пример демонстрирует некоторые флаги:

double d = 1.321e9;

int n = 1024;

void main(){ // Вывести значения cout << ”d = ” << d << ‘\n’ << ”n = ” << n << ‘\n’;

// Изменить флаги и вывести значения снова cout.setf(ios::hex | ios::uppercase);

cout.setf(ios::showpos);

cout << ”d = ” << d << ‘\n’ ;

cout << ”n = ” << n << ‘\n’;

} При выполнении программа выводит на экран:

d = 1.321е+n = d = +1.321E+n = Система ввода-вывода C++ предусматривает еще один способ форматирования потока. Этот способ основан на использовании манипуляторов ввода-вывода. Список манипуляторов и их назначение приведены в табл. 7. Манипуляторы ввода-вывода представляют собой просто вид функций-членов класса ios, которые, в отличие от обычных функций-членов, могут располагаться внутри инструкций вводавывода. В связи с этим ими пользоваться обычно удобнее.

Таблица Манипуляторы ввода-вывода и их назначение Манипулятор Использование Назначение dec Ввод-вывод Устанавливает флаг dec endl Вывод Вставляет символ новой строки и очищает буфер ends Вывод Вставляет символ конца flush Вывод Очищает буфер потока hex Ввод-вывод Устанавливает флаг hex oct Ввод-вывод Устанавливает флаг oct resetiosflags Ввод-вывод Сбрасывает ios-флаги в соответ(iosbase::long mask) ствии с mask Setbase (int base) Ввод-вывод Задает основание системы счисления для целых (8, 10, 16) Продолжение табл. Манипулятор Использование Назначение Setfill (int c) Ввод-вывод Устанавливает символзаполнитель setiosflags Ввод-вывод Устанавливает ios-флаги в соот(iosbase::long mask) ветствии с mask setprecision (int n) Ввод-вывод Устанавливает точность чисел с плавающей точкой setw(int n) Ввод-вывод Устанавливает минимальную ширину поля ws Ввод Устанавливает пропуск символов-заполнителей За исключением setw (), все изменения в потоке, внесенные манипулятором, сохраняются до следующей установки.

Для доступа к манипуляторам с параметрами необходимо включить в программу стандартный заголовочный файл iomanip.h. При использовании манипулятора без параметров скобки за ним не ставятся, так как на самом деле он представляет собой указатель на функциючлен, который передается перегруженному оператору <<.

Рассмотрим пример, демонстрирующий использование манипуляторов.

#include #include #include void main() { double x;

cout << setprecision(4);

cout << setfill(‘0’);

cout << ” x sqrt(x) x^2\n\n”;

for (x=1.0; x < 6.5; x++) { cout << setw(7) << x << ” ”;

cout << setw(7) << sqrt(x) << ” ”;

cout << setw(7) << x*x << ”\n”;

} } Этот пример функционально полностью эквивалентен приведенному ранее, но для управления форматом вывода использует манипуляторы, а не функции форматирования.

Манипулятор setw(), как и форматирующая функция width(), может помочь избежать переполнения строки-приемника при вводе символьных строк:

const int SIZE = 50;

...

char array[SIZE];

cin>>setw(sizeof(array)); // Или cin.width(sizeof(array));

// Ограничивает число вводимых символов... // и позволяет избежать выхода // за границу массива.

cin >> array;

27.5. Файловый ввод-вывод с использованием потоков Для осуществления операций с файлами предусмотрено три класса: ifstream, ofstream и fstream. Эти классы являются производными, соответственно, от классов istream, ostream и iostream. Поскольку эти последние классы, в свою очередь, являются производными от класса ios, классы файловых потоков наследуют все функциональные возможности своих родителей (перегруженные операции << и >> для встроенных типов, функции и флаги форматирования, манипуляторы и пр.).

Для реализации файлового ввода-вывода нужно включить в программу заголовочный файл fstream.h.

Существует небольшое отличие между использованием предопределенных и файловых потоков. Файловый поток должен быть связан с файлом прежде, чем его можно будет использовать. С другой стороны, предопределенные потоки могут использоваться сразу после запуска программы, даже в конструкторах статических классов, которые выполняются даже раньше вызова функции main(). Можно позиционировать файловый поток в произвольную позицию в файле, в то время как для предопределенных потоков это обычно не имеет смысла.

Для создания файлового потока эти классы предусматривают следующие формы конструктора:

создать поток, не связывая его с файлом:

ifstream();

ofstream();

fstream();

создать поток, открыть файл и связать поток с файлом:

ifstream(const char *name, ios::openmode mode = ios::in) ;

ofstream(const char* name, ios::openmode mode=ios::out | ios::trunc);

fstream(const char * name, ios::openmode mode = ios::in | ios::out);

Чтобы открыть файл для ввода или вывода, можно использовать вторую форму нужного конструктора fstream fs(”FileName.txt”);

или вначале создать поток с помощью первой формы конструктора, а затем открыть файл и связать поток с открытым файлом, вызвав функцию-член open(). Эта функция определена в каждом из классов потокового ввода-вывода и имеет следующие прототипы:

Pages:     | 1 |   ...   | 13 | 14 || 16 | 17 |










© 2011 www.dissers.ru - «Бесплатная электронная библиотека»

Материалы этого сайта размещены для ознакомления, все права принадлежат их авторам.
Если Вы не согласны с тем, что Ваш материал размещён на этом сайте, пожалуйста, напишите нам, мы в течении 1-2 рабочих дней удалим его.