30 Создание шаблонов функций и классов.

Шаблоны

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

Что такое шаблоны.

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

template<class Type>

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

template<class  Type1,   class  Type2,   class  Type3>

Существует два типа шаблонов: шаблоны функций и шаблоны классов.

Создание шаблонов функций

Шаблон функции начинается со строки template, за которой следует объявление функции. В строке template указываются типы аргументов, которые будут использоваться при вызове функции, следовательно, в объявлении функции должно быть определено, как эти аргументы будут передаваться функции в качестве параметров. Каждый параметр, указанный в строке template, должен быть использован в объявлении функции. Обратите внимание на тип Type1,  стоящий непосредственно перед именем функции. Type1 - это держатель места, определяющий тип возвращаемого функцией значения, который будет изменяться в зависимости от способа  использования шаблона

Пример 1: «Основная форма шаблона функции»

template<class  Typel,   class  Type2>

Type1  МyFunction(Type1  data1,   Type1   data2,   Type2   data3)

{

//   Здесь   поместите   текст  функции.

}

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

Пример 2:

#include<iostream.h>

template<class Type>

Type Min(Type arg1, Type arg2)

{

Type min;

if (arg1< arg2)

min= arg1;

else

min= arg2;

return min;

}

int main()

{

cout <<Min(15,25)<<endl;

cout <<Min(254.78,12.983)<<endl;

cout <<Min(‘A’,’Z’)<<endl;

return 0;

}

В шаблоне функции Min() тип данных Type используется не только в списках параметров и аргументов функции, но также и для объявления локальных переменных в основном тексте функции. Это обеспечивает возможность использования параметров типа шаблона аналогично любому другому конкретному типу данных, такому как int или char.

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

Еще один источник проблем заключается в некорректном вызове функции — когда аргументы, предоставляемые шаблону, используются не так, как вы предполагали. Например, что произойдет, если в функцию main() добавить приведенную ниже строку?

Cout << Min("APPLE",   "ORANGE") << endl;

На первый взгляд, результатом выполнения приведенной выше строки будет вывод на экран значения APPLE. На самом же деле, выполнение этой строки может привести, а может и не привести к ожидаемому результату Почему? Да потому, что "APPLE" и "ORANGE" являются строковыми константами, представленными указателями на char. Это означает, что программа будет успешно откомпилирована, при этом компилятор создаст версию функции Min(), которая будет сравнивать два указателя на тип char. Однако существует большая разница между сравнением двух указателей и сравнением данных, на которые они указывают. Если получится так, что строка "ORANGE" будет хранится по адресу меньшему, чем адрес строки "APPLE", то результатом работы данной версии функции Min() будет "ORANGE".

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

Пример 3:

#include<iostream.h>

#include<string.h>

template<class Type>

Type Min(Type arg1, Type arg2)

{

Type min;

if (arg1< arg2)

min= arg1;

else

min= arg2;

return min;

}

char* Min(char* arg1, char* arg2)

{

char* min;

int result = strcmp(arg1, arg2);

if (result < 0)

min = argl;

else

min = arg2;

return min;

}

int main()

{

cout << Min(15, 25) << endl;

cout << Min(254.78, 12.983) << endl;

cout << Min('A', 'Z') << endl;

cout << Min("APPLE", "ORANGE") << endl;

return ();

}

Hosted by uCoz