• Авторизация


Шаблоны функций и классов 24-06-2009 16:23 к комментариям - к полной версии - понравилось!




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

int Abs(int n)
{
 if (n<0) return -n;
 return n;
}
float Abs(float n)
{
 if (n<0) return -n;
 return n;
}
void main()
{
 int a=-2;
 int a1=2;
 float b=-4.05;
 float b1=3.2;
 cout<<Abs(a)<<" "<<Abs(a1)<<endl;
 cout<<Abs(b)<<" "<<Abs(b1)<<endl;
}

В этом случае, функция Abs перегружена для разных типов (int и float). Но реализация функции в обоих случаях одинакова. Чем же нам могут помочь шаблоны.

template <class T> T Abs(T n)
{
 if (n<0) return -n;
 return n;
}

Релизацию функции main мы можем оставить той же самой. В обоих случаях, у нас срабатывает один и тот же шаблон, т. е. независимо от типа переменных. Ключевое слово class может быть заменено на type. «Т» - это идентификатор типа. «Abs» - идентификатор функции. Обратите внимание на то, что T в данном случае определяет и тип возвращаемого значения функции Abs и тип параметра функции.
Как быть, если в списке параметров функции нам может понадобится использовать разные типы данных. Функция, возвращающая большее из значений:

template <class T1, class T2> T1 Max(T1 a, T2 b)
{
 if (a<b) return b;
 return a;
}
void main()
{
 int a=-2;
 int a1=2;
 float b=-4.05;
 float b1=3.2;
 cout<<Max(a,b)<<endl; //-2
 cout<<Max(a1,b1)<<endl; //3
}

Здесь нужно понимать, что возвращать функция будет значение типа T1. Т. е. если первый параметр имеет тип int, то и возвращать функция будет тип int. При этом произойдет временное преобразование типов.

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

template <class anyt>
int Find(anyt *a,anyt f, int n)
{
 for (int i=0;i<n;i++)
 if (a[i]==f) return i;
 return -1;
}
void main()
{
 int a[3]={10,15,20};
 double b[3]={1.5,5.4,6.3};
 char c[3]={'z','x','c'};
 cout<<Find(a,15,3)<<endl; //1
 cout<<Find(b,1.5,3)<<endl; //0
 cout<<Find(c,'c',3)<<endl; //2
 cout<<Find(a,0,3)<<endl; //-1
}

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

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

template <class anyt> 
class Bank
{
 public:
 anyt a;
 Bank(anyt na):a(na) {}
 void Show ()
 {
 cout<<a<<endl;
 }
};
void main()
{
 int a=15;
 double b=1.4;
 char c='f';

Тип anyt везде будет заменен тем типом, который используется в данный момент. А, вот создание объектов будет отличаться. При создании объектов, этот тип надо указывать.

Bank <int> objint(a);
Bank <double> objdouble(b);
Bank <char> objchar(c);
objint.Show(); //15
objdouble.Show(); //1.4
objchar.Show(); //f

Можно передавать параметры прямо в конструктор при создании объектов, т. к. тип опеределен, проблем с определением типа не будет.

Bank <int> objint(15);
Bank <double> objdouble(1.4);
Bank <char> objchar('f');
Как быть, если нам нужно хранить несколько неопределенных предположительно различающихся типов? Так же, как с шаблонами функций, описываем их в шаблоне и при создании объектов:

template <class type1, class type2>
class Bank
{
 public:
 type1 a;
 type2 b;
 Bank(type1 na, type2 nb):a(na),b(nb) {}
 void Show ()
 {
 cout<<a<<" "<<b<<endl;
 } 
};
void main()

 Bank <int, char> obj(15,'c');
 Bank <double, int> obj1(22.22,44); 
 obj.Show(); //15 c
 obj1.Show(); //22.22 44
}

Этот класс имеет только один метод. Метод ничего не возвращает и его список параметров пуст. Как быть, если нам нужен метод, использующий определенные нами типы. Создадим такой метод:

 void Set(type1 na, type2 nb)
 {
 a=na;
 b=nb;
 }
obj.Set(20,'d');
 obj.Show(); //20 d

Если же описание функции Set находится вне класса, то нужно использовать другой синтаксис. Оставим в классе прототип метода
void Set(type1, type2);

А перед описанием вне класса, мы должны использовать те же строчки, что мы используем перед описанием класса:

 template <class type1, class type2>
void Bank <type1, type2>::Set(type1 na, type2 nb)
 {
 a=na;
 b=nb;
 }

Эти строки должны присутствовать перед каждым методом, описанным вне класса.


 

вверх^ к полной версии понравилось! в evernote


Вы сейчас не можете прокомментировать это сообщение.

Дневник Шаблоны функций и классов | TheLenka - Дневник Рыжей Девчонки | Лента друзей TheLenka / Полная версия Добавить в друзья Страницы: раньше»