Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Функции-шаблоны (родовые функции)
Определение. Если функции выполняют одинаковые действия, но над данными разных типов, то можно определить одну функцию-шаблон. Определение имеет формат template < class X [, class Y,…]> имя_функции {определение_функции} Причем вместо типа какого-либо аргумента (или всех) или возвращаемого значения может стоять X, Y,…, где X, Y,… – идентификаторы для обозначения произвольного типа данных. Рассмотрим такую задачу: отсортировать массив целых чисел и строк методом пузырька. Вообще говоря, потребовалось бы создать 2 функции для сортировки каждого массива и 2 для обмена двух значений, т.е. 4 функции. Вместо этого напишем 2 функции-шаблона. Определим дополнительно еще 2 функции шаблона – для нахождения max элемента в массиве данных и вывода на экран двух значений данных разного типа.
enum boolean {FALSE, TRUE}; #include "string.hpp" #include "complex.hpp" template <class T> inline void Swap(T & a, T & b) {T c; c = a, a = b, b = c; }
template <class T> T Max(T * a, int n) {int i;T max = a[0]; for(i = 1; i < n; i++) if (a[i] > max) max = a[i]; return max; }
template <class T> void Bul_bul(T * a, int n) // улучшенный «пузырек» с флагом f
{int i, j, f; for(i = 0, f = 1; i < n – 1 && f; i++) for(j = f = 0; j < n – i – 1; j++) if (a[j] > a[j + 1]) {Swap(a[j], a[j + 1]); f = 1;} }
template <class X, class Y> void out2(X a, Y b) {cout << a << ' ' << b; }
Как же будет работать компилятор? При вызове функций-шаблонов в зависимости от типов фактических аргументов компилятор создает различные версии каждой из этих функций. Говорят – компилятор создает порожденную функцию. Процесс генерации порожденной функции называют созданием экземпляра функции. Таким образом, порожденная функция – это конкретный экземпляр функции-шаблона.
void main() { Complex b[5] = {Complex(4, 2), Complex(-3, 4), 1, -2}; String s[5] = {"Петров", "Сибирякова", "Горцев", "Савин", "Буторина"}; int a[10] = {5, 3, 9, 6, 2, 0, 1152, 7, 4}, i; cout << "\n Мax среди строк " << Max(s, 5); // Генерируется экземпляр String Max(String*, int) cout << "\n Мax среди целых чисел " << Max(a, 9); // Генерируется экземпляр int Max(int *, int) Bul_bul(s, 5); // Генерируется экземпляр void Bul_bul(String *, int); cout << "\nОтсортированные строки "; for(i = 0; i < 5; i++) out2(s[i], ' '); // генерируется экземпляр void out2(String, char); Bul_bul(a, 9); // генерируется экземпляр void Bul_bul(int *, int);
cout << "\nОтсортированные целые числа\n"; for(i = 0; i < 9; i++) out2(a[i], ' '); // генерируется экземпляр void out2(int, char); cout << "\nКомплексные числа\n"; for(i = 0; i < 5; i++) out2(b[i], " "); // генерируется экземпляр void out2(Complex, char *) out2(endl, "*********"); // генерируется экземпляр void out2(char, char *) getch(); }
При порождении экземпляров функции-шаблона сортировки Bul_bul(...) компилятор сгенерирует также 2 функции Swap – Swap (String &, String &) и Swap(int &, int &).
Программа будет работать при выполнении следующих условий: 1) в классе String должна быть перегружена операции сравнения на >; 2) в классах String и Complex должна быть перегружена операция потокового вывода <<; 3) в классе String, кроме того, должна быть перегружена операция =. Заметим, что функции-шаблоны напоминают перегруженные, но они по своим возможностям более ограничены. В теле таких функций должен быть одинаковый код (тело функции), а перегруженные функции могут содержать различные действия. Классы-шаблоны Так же, как и функции-шаблоны, могут быть определены и классы-шаблоны. Определение. Класс-шаблон – это класс, в котором одни и те же член-данные могут быть разных типов, а действия над ними – одинаковые. Формат определения класса-шаблона template < class X, class Y,...> class имя_класса { X определение член-данных; Y определение член-данных; ....... }; Здесь X и Y – условное обозначение типов данных. Использование такого класса в функциях следующее: имя_класса <конкретные_типы> имя_объекта[(арг-ты констр-а)]; При компиляции для каждого списка типов данных, указанного в < >, будет создан свой экземпляр класса. Рассмотрим пример класса-шаблона Stack. В стек кладутся целые и комплексные числа, строки.
enum boolean {FALSE, TRUE}; #include "string.hpp" #include "Complex.hpp" template <class T> class Stack { T *a; int max, n; public: Stack(int k = 50) {a = new T [max = k]; n = 0; } ~Stack() {delete [ ]a;} // деструктор Stack(Stack<T> &); // конструктор копирования Stack <T> operator = (Stack <T>); void Push(T b) // положить в стек элемент b {if (Full()) {cout << "Стек переполнен!"; return;} a[n++] = b;
} T Pop() // удалить элемент из стека {if (!isEmpty()) return a[--n];} T Top() // взять значение с вершины стека {return a[n - 1];} boolean isEmpty() // стек пуст? {if (n = = 0) return TRUE; return FALSE; } boolean Full(); // стек заполнен? friend ostream & operator << (ostream &, Stack <T> &); // потоковый вывод };
template <class T> Stack< T>:: Stack(Stack<T> & b) {int i; max = b.max; n = b.n; a= new T[max]; for(i = 0; i < n; i++) a[i] = b.a[i]; }
template <class T> boolean Stack<T>:: Full() { if (n = = max) return TRUE; // да, заполнен return FALSE; // нет, не заполнен }
template <class T> ostream & operator << (ostream & r, Stack <T> & b) { int i; if (b.isEmpty()) {r << "\nстек пуст"; return r;} for(i = 0; i < b.n; i++) cout << ' ' << b.a[i]; return r; }
template <class T> Stack<T> Stack<T>:: operator = (Stack<T> b) {if (& b!= this) {delete []a; a = new T[max = b.max]; n = b.n; for(int i = 0; i < n; i++) a[i] = b.a[i]; return *this; } }
void main() {Stack <Complex> c(5); // cоздается экземпляр стека комплексных чисел Stack <String> s(5); // cоздается экземпляр стека строк Stack <int> a(2), c; // стек целых чисел Stack <float> b(3); // стек вещественных чисел String b4("bbbb"); // строка “bbbb” int i; c.Push(Complex(2, 3)); // компл. число 2 + 3 * i => в стек комплексных чисел c.Push(3.5); // комп. число 3.5 + 3.5 * i => в стек комплексных чисел s. Push(«dddddd»); // строка “dddddd” => в стек строк s.Push(b4); // строка “bbbb” => в стек строк a.Push(77); // число 77 => в стек целых чисел a.Push(9); // число 9 => в стек целых чисел a.Push(-10); // Сообщение «Стек переполнен!” cout << "\n Стек комплексных чисел "; cout << c; // работают 2 перегруженные операции потокового вывода << для классов Stack и Complex cout<<"\n Стек строк: "; while (!s.isEmpty()) // пока стек не пуст cout << s.Pop(); // работает перегруженная в классе String операция << //Стек строк опустел c = a; // перегруж. операция = переписывает стек целых чисел a в c cout << "\n Стек целых чисел" << c; cout << ”\n В вершине стека число “ << a.Top(); cout << "\nСтек вещественных чисел b = " << b; }
Замечание. Так как действия над данными в классах-шаблонах одинаковые, а типы данных могут быть произвольные, то такие классы еще называют контейнерными. В настоящее время существует большой набор стандартных классов-шаблонов: стеки, очереди, деревья, строки, упорядоченные массивы и др.
|
||||||
Последнее изменение этой страницы: 2021-12-07; просмотров: 51; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.224.39.32 (0.014 с.) |