Главная Случайная страница


Полезное:

Как сделать разговор полезным и приятным Как сделать объемную звезду своими руками Как сделать то, что делать не хочется? Как сделать погремушку Как сделать так чтобы женщины сами знакомились с вами Как сделать идею коммерческой Как сделать хорошую растяжку ног? Как сделать наш разум здоровым? Как сделать, чтобы люди обманывали меньше Вопрос 4. Как сделать так, чтобы вас уважали и ценили? Как сделать лучше себе и другим людям Как сделать свидание интересным?


Категории:

АрхитектураАстрономияБиологияГеографияГеологияИнформатикаИскусствоИсторияКулинарияКультураМаркетингМатематикаМедицинаМенеджментОхрана трудаПравоПроизводствоПсихологияРелигияСоциологияСпортТехникаФизикаФилософияХимияЭкологияЭкономикаЭлектроника






Форматированный ввод





Библиотека iostream содержит средства, позволяющие форматировать вводимые данные (представлять их в различных системах счисления, с заданной точностью, выравнивать и т.д.).

Форматирование осуществляется несколькими функциями и флагами, заданными в классе ios битами переменной состояния форматирования.

class ios {

...

public:

enum

{

skipws=0x0001, // пропускать пробелы при вводе

left=0x0002, // прижать к левому краю поля

right=0x0004, // прижать к правому краю поля

internal=0x0008,

// выравнивание между знаком и значением

dec=0x0010, // десятичная система счисления

oct=0x0020, // восьмеричная система счисления

hex=0x0040,

// шестнадцатеричная система счисления

showbase=0x0080, // показать базу счисления

showpoint=0x0100, // отобразить десятичную точку

uppercase=0x0200, // использовать заглавные

// буквы при выводе формата (E и Х)

showpos=0x0400, // печатать плюс перед

// положительными числами

scientific=0x0800, // для чисел с плавающей

// запятой использовать нотацию с буквой Е

fixed=0x1000, // для чисел с плавающей

// запятой использовать нотацию 1.234

unitbuf=0x2000,

// выгрузить все потоки после ввода

stdio=0x4000,

// выгрузить все потоки после вывода

}; //enum

}; //ios

Любой флаг можно установить или сбросить с помощью перегружаемых функций setf и unsetf.

Пример.

long ios:: etf(long);

long ios:: setf(long, long);

Первый аргумент задает конкретный бит, который нужно установить, он может быть одним из флагов, заданных в перечислении. Чтобы включить сразу несколько флагов, их нужно связать побитовой операцией | (ИЛИ).

Пример.

cout.setf(ios:: oct | ios:: left);

Второй аргумент задает группу флагов, которые необходимо сбросить перед тем, как выполнить установку битов, заданных первым аргументом. Эти группы следующие:

Имя аргумента Очищаемые флаги Действие флагов
ios:: basefield ios:: hex ios:: oct ios:: dec   для целых
ios:: floatfield ios:: fixed ios:: scientific для чисел с плавающей запятой
ios:: adjustfield ios:: left ios:: right ios:: internal   для форм выдачи

Флаги сбрасываются вторым аргументом в том случае, когда они не могут быть заданы одновременно (например, десятичная и шестнадцатеричная система счисления).

Пример.

cout.setf(ios:: hex, ios:: basefield);

В данном случае сначала сбросятся в ноль все биты, относящиеся к системе счисления, а затем установится нужный бит.

Функция setf возвращает предыдущее состояние флага форматирования в виде числа long. Функция unsetf очищает биты признаков, возвращает значения старых признаков в виде числа long.

Пример.

long old=cout.setf(ios:: left,

ios:: adjustfiels);

...

cout.setf(old, ios:: adjustfiels);

// восстанавливает запомненное состояние флага

Функции для форматирования входят в класс ios.

1) Задание ширины поля вывода:

int ios:: width(int w);

int ios:: width();

Первая функция устанавливает ширину поля вывода в w символов и возвращает предыдущую ширину, если ширины не хватает, то она игнорируется и печатаются все символы, если ширина больше – лишние символы заполняются «_».

Пример.

int c1=29786, c2=7834;

int old=cout.width(10); // Запоминает старую

// ширину и устанавливает новую 10.

cout<<c1<<c2<<"\n";

cout.width(old);

// Восстанавливает прежнюю ширину 0.

cout<<c1<<c2<<"\n";

Результат:

29786 7834

Вторая функция width() - только возвращает текущую ширину.

Установленная ширина вывода сбрасывается в 0 после выполнения любой операции вывода.

Пример.

int a,b;

cout.width(7);

cout<<a<<b; // Ширина 7 действительна только для a

// переменная b использует ширину по умолчанию 0

2) Назначение символа-заполнителя лишних позиций при выводе данных (по умолчанию пробел, но его можно заменить). Функция fill – член класса ios.

Пример.

int l=7834;

cout.fill('#');

cout.width(8);

cout<<l; // ####7834

3) Программист может регулировать число цифр после десятичной точки, если число выводится в обыкновенной нотации. Для этого используется член-функция precision() класса ios.

Прототипы:

int precision(int);

int precision();

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

Второй формат – возвращает текущее количество знаков после точки.

Пример.

cout.precision(3);

cout<<5.762415; // Результат 5.762

Если необходимо не усекать завершающие нули, используется флаг ios:: showpoint.

Пример.

cout.setf(ios:: showpoint);

cout<<77.00; // Результат 77.000000

Пример.

cout.setf(ios:: showpoint);

cout.precision(12);

cout<<77.00<<"\n";

cout<<"После точки напечатано"<<cout.precision()<<

"цифр \n";

Манипуляторы.

Использование манипуляторов – это альтернативный способ форматированного ввода/вывода, основанный на механизме перегружаемых функций. Манипуляторы облегчают форматированние ввода/вывода тем, что могут вставляться в цепочку операторов << и >>.

Для использования манипуляторов необходимо включить в программу директиву:

#include<iomanip.h>

Манипуляторы бывают простые и параметризованные.

Имя Действие Примечание
dec Устанавливает десятичную систему счисления Для ввода/вывода
hex Устанавливает шестнадцатеричную систему счисления Для ввода/вывода
oct Устанавливает восьмеричную систему счисления Для ввода/вывода
ws Позволяет вводить пробельные символы Для ввода
endl Вставляет символ новой строки, выгружает поток Для вывода
ends Вставляет символ конца строки '\0' Для вывода
flush Выгружает поток ostream Для вывода
setbase(int base) Преобразует систему счисления к основанию base (8, 10, 16) Для вывода
resetiosflags(long) Сбрасывает биты признаков, определяемые аргументом Для ввода/вывода
setiosglags (long) Устанавливает биты признаков, задаваемые аргументом Для ввода/вывода
setfill (int) Устанавливает символ-заполнитель Для вывода
setprecision (int) Устанавливает точность для чисел с плавающей точкой Для вывода
setw(int) Устанавливает ширину поля Для вывода

Время действия каждого манипулятора начинается со времени его появления в строке ввода/вывода до его отмены.

Пример.

cout<<hex<<a<<b<<c; // Действие манипулятора hex

// распространяется на переменные a,b,c

Пример.

#include<iostream.h>

#include<iomanip.h>

void main()

{cout<<setw(5)<<setfill('-')<<setbase(16)<<10

<<endl;

// Результат ----а

cout<<setiosflags(ios:: uppercase | ios::

internal | ios:: showbase)<<setfill('-

')<<setbase(16)<<setw(5)<<10<<endl;

// Результат OX--A

cout<<setiosflags(ios:: fixed)<<setprecisoon(1)

<<12.12345<<endl;

// Результат 12.1

}

 

Шаблоны функций

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

Цель введения шаблонов функций - автоматизация создания функций, которые могут обрабатывать разнотипные данные. В отличие от механизма перегрузки, когда для каждой сигнатуры определяется своя функция, шаблон семейства функций определяется один раз, но это определение параметризуется. Параметризовать в шаблоне функций можно тип возвращаемого функцией значения и типы любых параметров, количество и порядок размещения которых должны быть фиксированы. Для параметризации используется список параметров шаблона.

В определении шаблона семейства функций используется служебное слово template. Для параметризации используется список формальных параметров шаблона, который заключается в угловые скобки <>. Каждый формальный параметр шаблона обозначается служебным словом class, за которым следует имя параметра (идентификатор).

Пример.

Определение шаблона функций, вычисляющих абсолютные значения числовых величин разных типов:

template <class type>

type abs(type x)

{return x>0? x: -x;}

Шаблон семейства функций состоит из двух частей - заголовка шаблона:

template <список_параметров_шаблона>

и из обыкновенного определения функции, в котором тип возвращаемого значения и типы любых параметров обозначаются именами параметров шаблона, введенных в его заголовке. Те же имена параметров шаблона могут использоваться и в теле определения функции для обозначения типов локальных объектов.

Пример.

В качестве еще одного примера рассмотрим шаблон семейства функций для обмена значений двух передаваемых им параметров.

template <class T>

void swap(Т* x, Т* у)

{Т z=*х;

*х=*у;

*у=z;

}

Здесь параметр T шаблона функций используется не только в заголовке для спецификации формальных параметров, но и в теле определения функций, где он задает тип вспомогательной переменной z.

Шаблон семейства функций служит для автоматического формирования конкретных определений функций по тем вызовам, которые транслятор обнаруживает в тексте программы.

Пример.

Если программист употребляет обращение abs(-10.3), то на основе приведенного выше шаблона компилятор сформирует такое определение функции:

double abs(double x)

{return x>0? х: -х;}

Далее будет организовано выполнение именно этой функции и в точку вызова в качестве результата вернется числовое значение 10.3.

Если в программе присутствует приведенный выше шаблон семейства функций swap и появится последовательность операторов:

long k=4, d=8; swap(&k, &d);

то компилятор сформирует определение функции:

void swap(long* x, long* у)

{long z=*x;

*x=*y;

*y=z;

}

Затем будет выполнено обращение именно к этой функции и значения переменных k, d поменяются местами.

Если в той же программе присутствуют операторы:

double a=2.44, b=66.3;

swap(&a, &b);

то сформируется и выполнится функция

void swap(double* x, double* у)

{double z=*x;

*x=*y;

*y=z;

}

Пример.

Проиллюстрируем сказанное о шаблонах на более конкретном примере. Рассмотрим следующую программу, в которой вспомним некоторые возможности функций, возвращающих значение типа "ссылка". Но тип ссылки будет определяться параметром шаблона:

#include <iostream.h>

// Функция определяет ссылку на элемент с

// максимальным значением:

template <class type>

type& rmax(int n, type d[])

{int im=0;

for (int i=1; i<n; i++)

im=d[im]>d[i]? im: i;

return d[im];

}

void main()

{int n=4;

int x[]={10, 20, 30, 14};

// Аргумент - целочисленный массив

cout<<"\n rmax(n,x)="<<rmax(n,x);

rmax(n,x)=0;

// Обращение с целочисленным массивом

for (int i=0; i<n; i++)

cout<<"\t x["<<i<<"]="<<x[i];

float arx[]={10.3, 20.4, 10.5};

// Аргумент - массив float:

cout<<"\n rmax(3,arx)<<"rmax(3,arx);

rmax(3,arx)=0;

// Обращение с массивом типа float

for (i=0; i<3; i++)

cout<<"\t arx["<<i<<"]="<<arx[i];

}

Результат выполнения программы

rmax(n,x)=30 x[0]=10 x[l]=20 x[2]=0 x[3]=14

rmax(3,arx)=20.4 arx[0]=10.3 arx[l]=0 arx[2]=10.5

В программе используются два разных обращения к функции rmax. В одном случае параметр - целочисленный массив и возвра­щаемое значение - ссылка типа int. Во втором случае фактический параметр - имя массива типа float и возвращаемое значение имеет тип ссылки на float.

По существу механизм шаблонов функций позволяет автоматизи­ровать подготовку определений перегруженных функций. При ис­пользовании шаблонов уже нет необходимости готовить заранее вес варианты функций с перегруженным именем. Компилятор автомати­чески, анализируя вызовы функций в тексте программы, формирует необходимые определения именно для таких типов параметров, которые использованы в обращениях. Дальнейшая обработка выполняется так же, как и для перегруженных функций.

Можно считать, что параметры шаблона функций являются его формальными параметрами, а типы тех параметров, которые исполь­зуются в конкретных обращениях к функции, служат фактическими параметрами шаблона. Именно по ним выполняется параметрическая настройка и с учетом этих типов генерируется конкретный текст определения функции. Однако, говоря о шаблоне семейства функций обычно употребляют термин "список параметров шаблона", не добавляя определения "формальных ".

Перечислим основные свойства параметров шаблона.

1.Имена параметров шаблона должны быть уникальными во всем определении шаблона.

2.Список параметров шаблона функций не может быть пустым, так как при этом теряется возможность параметризации и шаблон функций становится обычным определением конкретной функции.

3.В списке параметров шаблона функций может быть несколько параметров. Каждый из них должен начинаться со служебного слова typename либо class.

Пример.

Допустим такой заголовок шаблона:

template <class type1, class type2>

Соответственно, неверен заголовок:

template <class type1, type2, type3>

4. Недопустимо использовать в заголовке шаблона параметры с одинаковыми именами, т.е. ошибочен такой заголовок:

template <class t, class t, class t>

5. Имя параметра шаблона (в наших примерах typel, type2 и т.д.) имеет в определяемой шаблоном функции все права имени типа, т.е. с его помощью могут специализироваться формальные параметры, определяться тип возвращаемого функцией значения и типы любых объектов, локализованных в теле функции. Имя параметра шаблона видно во всем определении и скрывает другие использования того же идентификатора в области, глобальной по отношению к данному шаблону функций. Если внутри тела определяемой функции необходим доступ к внешним объектам с тем же именем, нужно применять операцию изменения области видимости.

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

Все параметры шаблона функций должны быть обязательно использованы в спецификациях параметров определения функции.

Пример.

Таким образом, будет ошибочным такой шаблон:

template <class A, class В, class C>

В func(A n, С m)

{В valu;

...

}

В данном неверном примере остался неиспользованным параметр шаблона с именем B. Его применений в качестве типа возвращаемого функцией значения и для определения объекта valu в теле функции недостаточно.

Определяемая с помощью шаблона функция может иметь любое количество непараметризованных формальных параметров. Может быть не параметризовано и возвращаемое функцией значение.

Пример.

В следующей программе шаблон определяет семейство функций, каждая из которых подсчитывает количество нулевых элементов одномерного массива параметризованного типа:

#include <iostream.h>

template <class D>

long count0(int, D*); // Прототип шаблона

void main()

{int A[]={1,0,6, 0, 4, 10};

int n=sizeof(A)/sizeof A[0];

cout<<"\n count0(n,A)="<<count0(n,A);

float X[]={10.0, 0.0, 3.3, 0.0, 2.1);

n=sizeof(X)/sizeof X[0];

cout<<"\n count0(n,X)="<<count0(n,X);

}

// Шаблон функций для подсчета количества

// нулевых элементов в массиве

template <class T>

long count0(int size, T* array)

{long k=0;

for (int i=0; i<size; i++)

if (int(array[i])==0) k++;

return k;

}

Результат выполнения программы:

count0(n,A)=2 count0(n,X)=2

В шаблоне функций count0 параметр T используется только в спецификации одного формального параметра array. Параметр size и возвращаемое функцией значение имеют явно заданные непараметризованные типы.

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

template <список_параметров_шаблона>

тип имя_функции (спецификация параметров);

В списке параметров прототипа шаблона имена параметров не обязаны совпадать с именами тех же параметров в определении шаблона. Это и продемонстрировано в программе.

При конкретизации шаблонного определения функции необходимо, чтобы при вызове функции типы фактических параметров, соответствующие одинаково параметризованным формальным параметрам, были одинаковыми.

Пример.

Для определенного выше шаблона функций с прототипом

template <class E> void swap(E,E);

недопустимо использовать такое обращение к функции:

int n=4; double d=4.3;

swap(n,d); // Ошибка в типах параметров

Для правильного обращения к такой функции требуется явное приведение типа одного из параметров:

swap(double(n),d); // Правильные типы параметров

это приведет к конкретизации шаблонного определения функций с параметром типа double.

При использовании шаблонов функций возможна перегрузка как шаблонов, так и функций. Могут быть шаблоны с одинаковыми именами, но разными параметрами. Или с помощью шаблона может создаваться функция с таким же именем, что и явно определенная функция. В обоих случаях "распознавание" конкретного вызова выполняется по сигнатуре, т.е. по типам, порядку и количеству фактических параметров.

При компиляции обращения к функции выбор подходящего определения среди перегруженных параметризованных или обычных функций происходит в три этапа:

1. Поиск обычной функции, типы параметров которой в точности соответствуют требуемым; если такая будет найдена, то обращение происходит к ней.

2. Поиск параметризованной функции, из которой можно породить данную функцию при точном соответствии параметров (без преобразования типов); если такая будет найдена, то обращение происходит к ней.

3. Поиск обычной функции, к типам формальных параметров которой наилучшим образом могут быть преобразованы типы фактических параметров вызова; если такая будет найдена, то обращение происходит к ней.

Если подходящего определения функции не будет найдено, то обращение к данной функции считается неопределенным. Если на каком-либо из этих трех шагов будет найдено более одного подходящего определения, то возникает неоднозначность.

 

Классы и шаблоны

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

Общая форма объявления параметризованного класса:

template <class тип_данных>

class имя_класса {...};

Основные свойства шаблонов классов.

1. Компонентные функции параметризованного класса автоматически являются параметризованными. Их не обязательно объявлять как параметризованные с помощью template.

2. Дружественные функции, которые описываются в параметризованном классе, не являются автоматически параметризованными функциями, т.е. по умолчанию такие функции являются дружественными для всех классов, которые организуются по данному шаблону.

3. Если friend-функция содержит в своем описании параметр типа параметризованного класса, то для каждого созданного по данному шаблону класса имеется собственная friend-функция.

4. В рамках параметризованного класса нельзя определить friend-шаблоны (дружественные параметризованные классы).

5. С одной стороны, шаблоны могут быть производными (наследоваться) как от шаблонов, так и от обычных классов, с другой стороны, они могут использоваться в качестве базовых для других шаблонов или классов.

6. Шаблоны функций, которые являются членами классов, нельзя описывать как virtual.

7. Локальные классы не могут содержать шаблоны в качестве своих элементов.

Шаблон семейства классов определяет способ построения отдельных классов подобно тому, как класс определяет правила построения и формат отдельных объектов. В определении класса, входящего в шаблон, особую роль играет имя класса. Оно является не именем отдельного класса, а параметризованным именем семейства классов.

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

Пример.

Рассмотрим векторный класс (в число данных входит одномерный массив). Какой бы тип ни имели элементы массива (целый, вещественный, с двойной точностью и т.д.), в этом классе должны быть определены одни и те же базовые операции, например доступ к элементу по индексу и т.д. Если тип элементов вектора задавать как параметр шаблона класса, то система будет формировать вектор нужного типа (и соответствующий класс) при каждом определении конкретного объекта.

Следующий шаблон позволяет автоматически формировать классы векторов с указанными свойствами:

template <class T> // Т - параметр шаблона

class Vector

{Т *data; // Начало одномерного массива

int size; // Количество элементов в массиве

public:

Vector(int); // Конструктор класса vector

~Vector()

{delete[] data;} // Деструктор

// Перегрузка операции "[]":

Т& operator[](int i)

{return data[i];}

};

// Внешнее определение конструктора класса:

template <class T>

Vector <T>:: Vector(int n)

{data=new T[n];

size=n;

}

Когда шаблон введен, у программиста появляется возможность определять конкретные объекты конкретных классов, каждый из которых параметрически порожден из шаблона.

Формат определения объекта одного из классов, порождаемых шаблоном классов:

имя_параметривованного_класса

<фактические_параметры_шаблона> имя_объекта

(параметры_конструктора);

Пример.

В нашем случае определить вектор, имеющий восемь вещественных координат типа double, можно следующим образом:

Vector <double> Z(8);

Проиллюстрируем сказанное следующей программой:

#include "template.vec" // Шаблон классов "вектор"

#include <iostream.h>

void main()

{// Создаем объект класса "целочисленный вектор":

Vector <int> X(5);

// Создаем объект класса "символьный вектор":

Vector <char> С(5);

// Определяем компоненты векторов:

for (int i=0; i<5; i++)

{X[i]=i;

C[i]=’A’+i;

}

for (int i=0; i<5; i++)

cout<<" "<<X[i]<<' '<<C[i];

}

Результат выполнения программы:

0A 1B 2С 3D 4E

В программе шаблон семейства классов с общим именем vector используется для формирования двух классов с массивами целого и символьного типов. В соответствии с требованием синтаксиса имя параметризованного класса, определенное в шаблоне (в примере Vector), используется в программе только с последующим конкретным фактическим параметром (аргументом), заключенным в угловые скобки. Параметром может быть имя стандартного или определенного пользователем типа. В данном примере использованы стандартные типы int и char. Использовать имя Vector без указания фактического параметра шаблона нельзя - никакое умалчиваемое значение при этом не предусматривается.

В списке параметров шаблона могут присутствовать формальные параметры, не определяющие тип, точнее - это параметры, для которых тип фиксирован.

Пример.

#include <iostream.h>

template <class T, int size=64>

class row

{T *data;

int length;

public:

row()

{length=size;

data=new T[size];

}

~row()

{delete[] data;}

T& operator[](int i)

{return data[i];}

};

void main()

{row <float,8> rf;

row <int,8> ri;

for (int i=0; i<8; i++)

{rf[i]=i;

ri[i]=i*i;

}

for (i=0; i<8; i++)

cout<<' '<<rf[i]<<' '<<ri[i];

}

Результат выполнения программы:

0 0 1 1 2 4 3 9 4 16 5 25 6 36 7 49

В качестве аргумента, заменяющего при обращении к шаблону параметр size, взята константа. В общем случае может быть использовано константное выражение, однако выражения, содержащие переменные, использовать в качестве фактических параметров шаблонов нельзя.

Реализация компонентной функции шаблона класса, которая находится вне определения шаблона класса, должна включать дополнительно следующие два элемента:

1. Определение должно начинаться с ключевого слова template, за которым следует такой же список_параметров_типов в угловых скобках, какой указан в определении шаблона класса.

2. За именем_класса, предшествующим операции области видимости (::), должен следовать список_имен_параметров шаблона.

template<список_типов>тип_возвр_значения

имя_класса<список_имен_параметров>::

имя_функции(список_параметров){...}

Date: 2016-05-13; view: 315; Нарушение авторских прав; Помощь в написании работы --> СЮДА...



mydocx.ru - 2015-2024 year. (0.006 sec.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав - Пожаловаться на публикацию