|
Программирование >> Динамические структуры данных
Семинар 8. Перефуэка и ш§>блоны функций if (read dbase( txt6.txt . dbase. l dbase. n record) !- 0 ) return 1: int option: int year: float pay: do { cout ............................... endl: cout 1 - Сведения no году рождения endl: cout 2 - Сведения no окладу endl: cout 3 - Выход endl: cin option: switch (option) { case 1: cout Введите год : cin year: . select(dbase. n record. year): break: case 2: cout Введите оклад : cin pay: select(dbase. n record. pay): break: case 3: return 0: default: cout Надо вводить число от 1 до 3 endl: } while (true): return 0: void select(Man dbase[]. const int n record. const int year) { cout Вывод сведений по году рождения endl: bool success - false: for (int i - 0: i < n record: i++) if (dbaseCi].birth year >- year) { print (dbaseCi]): success - true: if ( .success) cout Таких сотрудников нет endl: void select(Man dbaseC]. const int n record. const float pay ){ cout Вывод сведений no окладу endl: bool success = false: for (int i = 0: i < n record: i++) if (dbaseCi].pay >- pay) { print (dbaseCi]): success = true: if (!success) cout Таких сотрудников нет endl: void print(Man m) { cout.setf(ios::fixed): cout.precision(2): Шаблоны функций cout setw(40) m.name * m.birth ear m.pay endl: int read dbase(const char * filename. Man dbaseC]. const int l dbase. int &n record) { char buf Cl buf + 1]: ifstream fin(filename. ios::in ios::nocreate): if (Ifin ){ cout Нет файла filename endl: return 1: } int i - 0: while (fin.getline(buf. l buf)) { strncpy(dbaseCi].name. buf. l name): dbaseCi].nameCl name] - *\0: dbaseCi].birth >ear - ato1(&bufCl name]): dbaseCi].pay - atof(&bufCl name + 1 ear]): 1++: if (i > 1 dbase) { cout Слишком длинный файл : return 2: } n record = i: fin.closeO: return 0: Добавьте в базу еще одно-два осмысленных поля (например, отдел, стаж или количество детей) и напишите еще одну перегруженную функцию для выборки по новому критерию. Если тип критерия будет такой же, как один из рассмотренных, то, чтобы компилятор мог различать варианты, можно добавить в функцию дополнительный параметр. Ниже приведены правила описания перегруженных функций. □ Перегруженные функции должны находиться в одной области видимости, иначе произойдет сокрытие аналогично одинаковым именам переменных во вложенных блоках. □ Перегруженные функции могут иметь параметры по умолчанию, при этом значения одного и того же параметра в разных функциях должны совпадать. В различных вариантах перегрзгженных функций может быть различное количество параметров по умолчанию. □ Функции не могут быть перегружены, если описание их параметров отличается только модификатором const или использованием ссылки. Шаблоны функций Итак, мы создали несколько перегруженных функций, а теперь предоставим аналогичную возможность компилятору: зададим шаблон функции, а компилятор пусть самостоятельно создает столько перегруженных функций, для скольких ти- пов данных нам потребуется вызвать шаблон. Конечно, этот фокус пройдет у нас только в том случае, если реализуемый алгоритм независим от типа данных. Таким образом, области применения перегрузки функций и шаблонов отличаются: перегруженные функции мы применяем для оформления действий, аналогичных по названию, но различных по реализации, а шаблоны - для идентичных действий над данными различных типов. Шаблон функции определяется следующим образом: template <class Туре> тип имя ([ списокпараиетров ]) { /* тело функции */ } Идентификатор Туре, задающий так называемый параметризованный тип, может использоваться как в остальной части заголовка, так и в теле функции. Параметризованный тип - это всего лишь фиктивное имя, которое компилятор автоматически заменит именем реального типа данных при создании конкретной версии функции. В общем случае шаблон функции может содержать несколько параметризованных типов <с1 ass Typel. class TypeZ. class ТуреЗ. ... >. Процесс создания конкретной версии функции называется инстанцированием шаблона или созданием экземпляра функции. Возможны два способа инстанциро-вания шаблона: а) явный, когда объявляется заголовок функции, в котором все параметризованные типы заменены на конкретные типы, известные в этот момент в программе, б) неявный, когда создание экземпляра функции происходит автоматически, если встречается фактический вызов функции. Для того чтобы вы прониклись разнообразием возможностей языка С++, упомянем, что шаблоны тоже можно перегружать, причем как шаблонами, так и обычными функциями. Задача 8.2. Шаблоны функций Написать программу, которая определяет максимальные элементы в одномерных массивах различных арифметических типов. Поиск максимума - весьма распространенная задача, и желание сделать для этого универсальную функцию естественно. Для этого достаточно простейшего шаблона с одним параметром-типом. В саму функцию будет передаваться два аргумента: указатель на массив и длина этого массива. #include <iostream.h> #include <string.h> template <class T> T Max(T *b. int n): int main(){ const int n = 20: int i. b[n]: cout Введите n целых чисел: endl: for (i = 0: i < n: i++) cin b[i]: cout Max(b. n) endl; double a[] = {0.22. 117.2. -0.08. 0.21. 42.5): cout Max(a. 5) endl; char *str = Sophisticated fantastic template : cout MaxCstr. strlen(str)) endl: return 0: template <class T> T Max(T *b, int n) { int imax = 0: for (int i = 1: i < n: i++) if (b[i] > b[imax]) imax = i: return b[imax]: Шаблон функции имеет имя Max. После ключевого слова tempi ate в угловых скобках перечисляются все параметры шаблона. В данном слзгчае параметр один. При инстанцировании шаблона (в данном случае - неявном), то есть когда компилятор будет создавать конкретный вариант функции, этот тип будет заменен конкретным стандартным или пользовательским типом. Соответствие устанавливается при вызове функции либо по типу аргументов, либо по явным образом указанному типу. Например, последний вызов функции можно записать так: cout Max<char>(str, strlen(str)); Этот способ применяется в тех случ2лх, когда тип не определяется по виду оператора вызова функции. Аналогично обычным параметрам функции, можно задавать значение параметра шаблона по умолчанию. ВНИМАНИЕ - При работе с многофайловым проектом нужно не забывать, что если какой-то шаблон функции имеет инстанцирование в нескольких исходных файлах, то определение этого шаблона должно повторяться в каждом из этих файлов. Поэтому обычно определение шаблона выносят в заголовочный файл и подключают его в нужных местах директивой #i ncl ude. Давайте повторим основные моменты этого семинара. 1. Перегрузкой функций называется использование нескольких функций с одним именем и различными типами параметров. 2. Перегрузка применяется, когда одно и то же по смыслу действие реализуется по-разному для различных типов или структур данных. 3. При написании перегруженных функций необходимо, чтобы в процессе поиска нужного варианта функции по ее вызову не возникало неоднозначности. Неоднозначность может возникнуть из-за преобразований типов, параметров по умолчанию и ссылок. 4. Функции не могут быть перегружены, если описание их параметров отличается только модификатором const или использованием ссылки. 5. Шаблоны функций применяются для записи идентичных действий над данными различных типов. 6. Инстанцирование шаблона функции - это создание компилятором конкретного варианта функции. 7. Шаблоны можно перегружать как шаблонами, так и обычными функциями. Задания Выполнить задания третьего и четвертого семинара, оформив каждый пункт задания в виде шаблона функции. Все необходимые данные для функций должны передаваться им в качестве параметров. Использование глобальных переменных в функциях не допускается. Привести примеры программ, использующих эти шаблоны для типов i nt, f 1 oat и doubl е. СЕМИНАР 9 Динамические структуры данных Теоретический материал: с. 114-127. На предыдущих семинарах мы рассматривали задачи, в которых необходимый для хранения данных объем памяти был известен либо до компиляции программы, либо до начала ввода данных. В первом случае память резервировалась с помощью операторов описания, во втором - с помощью функций выделения памяти. В обоих случаях выделялся непрерывный участок памяти. Если до начала работы с данными невозможно определить, сколько памяти потребуется для их хранения, память выделяется по мере необходимости отдельными блоками, связанными друг с другом при помощи указателей. Такой способ организации данных называется динамическими структурами данных, поскольку их размер изменяется во время выполнения программы. Из динамических структур в программах чаще всего используются различные линейные списки, стеки, очереди и бинарные деревья. Они различаются способами связи отдельных элементов и допустимыми операциями над ними. Динамическая структура может занимать несмежные участки оперативной памяти. В процессе работы программы элементы структуры могут по мере необходимости добавляться и удаляться. Элемент любой динамической структуры данных состоит из полей, часть из которых предназначена для связи с соседними элементами. Вот, например, как выглядит описание элемента линейного списка для хранения целых чисел: struct Node { int d: Node *p: В зависимости от решаемой задачи в программах применяются различные виды динамических структур. Рассмотрим их на примерах.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |