Использование шаблонов функций

Стек

Стек - одна из полезных структур данных. Для стека характерны такие операции как вставка и удаление данных, но выполняются они только над самым верхним элементом (вершиной стека). Такой порядок называется "первым вошел, последним вышел".

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

struct stack
{
char s[1000];
int top;
};

Теперь создадим функцию reset, задача которой - инициализация. В ней достаточно переменной top присвоить значение -1. В качестве параметра ей будет передаваться указатель на структуру (при использовании указателя для доступа к членам структуры используется не ".", а оператор "->").

void reset(stack* st)
{
st->top = -1;
}

Так же нужны функции push (вставить) и pop (извлечь).

void push(stack* st, char s)
{
++st->top;
st->s[st->top] = s;
}
char pop(stack* st)
{
--st->top;
return st->s[st->top];
}

Теперь напишем функцию main, чтобы проверить нашу версию стека. Функция будет печатать строку в обратном порядке.

main()
{
char str[] = "My name is Gena";
int count = sizeof(str);
stack My_stack;
reset(&My_stack);
for(int i = 0; i < count; i++)
{
push(&My_stack, str[i]);
}
while(My_stack.top != -1)
{
cout << pop(&My_stack);
}
cout << endl;
}

Полностью текст программы должен выглядеть так:

#include <iostream.h>

struct stack
{
char s[1000];
int top;
};

void reset(stack* st)
{
st->top = -1;
}

void push(stack* st, char s)
{
++st->top;
st->s[st->top] = s;
}

char pop(stack* st)
{
--st->top;
return st->s[st->top];
}

main()
{
char str[] = "My name is Gena";
int count = sizeof(str);
stack My_stack;
reset(&My_stack);
for(int i = 0; i < count; i++)
{
push(&My_stack, str[i]);
}
while(My_stack.top != -1)
{
cout << pop(&My_stack);
}
cout << endl;
}

Структуры в С++ могут иметь в качестве своих членов (в предыдущем примере это s и top) не только переменные но и функции. Для этого объявления функций вставляются в объявление структуры, например предыдущий пример стека можно объявить так:

struct stack
{
char s[1000];
int top;
void reset()
{
top = -1;
}
void push(char c)
{
++top;
s[top] = c;
}
char pop()
{
--top;
return s[top];
}
};

Функции-члены записаны так же, как обычные функции. Отличие лишь в том, что теперь они могут использовать переменные и функции "как есть", им не нужно передавать в качестве параметров такие переменные как s и top. Обращаются к функциям-членам так же, как и к обычным членам: с помощью оператора ".", а указатели - с помощью оператора "->". Приведем несколько фрагментов кода:

stack My_stack;
My_stack.reset();

stack *pMy_stack = &My_stack;
pMy_stack->push('A');

Функции-члены, которые определены внутри структуры, являются встраиваемыми. Обычно, столь маленькие, часто используемые функции определяются внутри структуры (как в предыдущем случае). Чтобы определить функцию-член вне структуры используется оператор "::". Например:

struct stack
{
char s[1000];
int top;
void reset();
void push(char c);
char pop();
};

void stack::reset()
{
top = -1;
}
void stack::push(char c)
{
++top;
s[top] = c;
}
char stack::pop()
{
--top;
return s[top];
}

Запись void stack::reset() говорит, что функция reset() принадлежит структуре stack. Благодаря оператору "::" можно задавать одинаковые имена функций для разных типов структур.

Шаблоны

Использование шаблонов функций

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

Основные концепции:

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

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

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

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

· В процессе компиляции компилятор C++ будет создавать в вашей программе функции с использованием типов, указанных в прототипах функций, которые ссылаются на имя шаблона.

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

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

template<class Т> Т mах(Т а, Т b)

{
if (а > b) return(а);
else return(b);
}

Буква T данном случае представляет собой общий тип шаблона. После определения шаблона внутри программы объявляются прототипы функций для каждого требуемого типа. В случае шаблона mах следующие прототипы создают функции типа float и int.

float max(float, float);
int max(int, int);

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

template<class Т> Т max(Т а, Т b)

{
if (a > b) return(а) ;
else return(b);
}

float max(float a, float b)

{
if (a > b) return(a) ;
else return(b);
}

Следующая программа МАХ_ТЕМР.СРР использует шаблон mах для создания функции типа int и float.

#include <iostream.h>

template<class T> Т mах(Т а, Т b)

{
if (a > b) return(a);
else return(b);
}

float max(float, float);

int max(int, int);

void main(void)

{
cout << "Максимум 100 и 200 равен " << max(100, 200) << endl;
cout << "Максимум 5.4321 и 1.2345 равен " << max(5.4321, 1.2345) << endl;
}

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

ШАБЛОНЫ, КОТОРЫЕ ИСПОЛЬЗУЮТ НЕСКОЛЬКО ТИПОВ

Предыдущее определение шаблона для функции max использовало единственный общий тип Т. Очень часто в шаблоне функции требуется указать несколько типов. Например, следующие операторы создают шаблон для функции show_array, которая выводит элементы массива. Шаблон использует тип Т для определения типа массива и тип Т1 для указания типа параметра count:

template<class T,class T1> void show_array(T *array,T1 count)

{
T1 index;
for (index =0; index < count; index++) cout << array[index] << ' ';
cout << endl;
}

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

void show_array(int *, int);
void show_array(float *, unsigned);

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

#include <iostream.h>

template<class T,class T1> void show_array( T *array,T1 count)

{
T1 index;
for (index =0; index < count; index++) cout << array[index] “ ' ';
cout << endl;
}

void show_array(int *, int);

void show_array(float *, unsigned);

void main(void)

{
int pages[] = { 100, 200, 300, 400, 500 };
float pricesH = { 10.05, 20.10, 30.15 };
show_array(pages, 5);
show_array(prices, 3);
}

Наши рекомендации