Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Дабораторная работа 19.doc
Скачиваний:
13
Добавлен:
11.04.2015
Размер:
113.66 Кб
Скачать

Шаблон функций

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

for(i=0; i<n; i++) a[i]=b[i];

Данный код можно на С автоматизировать простой макрокомандой.

 

#define COPY(A,B,N) { int i; for(i=0; i<N; i++) A[i]=B[i]; }

 

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

template <class TYPE>

void copy(TYPE a[],TYPE b[],int n) {

for(int i=0; i<n; i++) a[i]=b[i];

}

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

double f1[50], f2[50];

copy(f1,f2,50);

char c1[25],c2[50];

copy(c1,c2,10);

int i1[75],i2[75];

copy(i1,i2,40);

char *ptr1, *ptr2;

copy(ptr1,ptr2,100);

copy(i1,f2,50); // error

copy(ptr1,f2,50); // error

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

copy(i1,(int *)f2,50);

Однако при этом будет получена несоответствующая форма копирования. Дело в том, что родовая процедура копирования должна получать в виде параметров два класса отличающегося типа.

template class T1, class T2>

void copy(T1 a[], T2 b[], int n) { for(int i=0; i<n; i++) a[i]=b[i]; }

В этой форме существует поэлементное преобразование. Оно обычно соответствует и наиболее безопасному преобразованию.

Совпадение сигнатуры и перегрузка

Часто родовая подпрограмма не может работать для специального случая. Следующая форма шаблона обмена (swapping) работает для базовых типов.

template <class T>

void swap(T &x, T& y) { T temp; temp=x; x=y; y=temp; }

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

int i.j;

char str1[100],str2[100];

complex c1,c2;

swap(i,j); // i, j -int допустимо

swap(с1,с2); // с1, с2 -complex допустимо

swap(str1[50],str2[33]); // обе -char допустимо

swap(str1,str2); // допустимо

swap(i, chj); // i, -int, ch -char не допустимо

Сделаем так, чтобы swap работала для строк, представляемых как символьные массивы; для этого опишем следующий специальный случай.

void swap (char *s1, char *s2) {

int len=(strlen(s1) >= strlen(s2)) ? strlen(s1): strlen(s2);

char *temp=new char [len+1]; strcpy(temp,s1); strcpy(s1,s2); strcpy(s2,temp); delete temp;

}

С добавлением такого явного случая, при вызове с точным соответствием сигнатуре swap(), имеется преимущество над точным соответствием, найденным с помощью подстановки шаблона.

Алгоритм выбора функции перегрузки следующий:

  1. Найти точное соответствие функции не-шаблону.

  1. Найти точное соответствие, использующее шаблон функции

  1. Обеспечить обычное разрешение параметра для функций не-шаблонов

Шаблоны классов

Дружественность

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

template <class T>

class matrix {

friend void foo_bar(); // универсальная

friend vect <T> product(vect <T> v); // создается экземпляр

};

Статические члены

Статические члены не универсальны, а специфичны для каждой реализации.

template <class T>

class foo {

public:

static int count;

};

template <class T> int foo::count=0;

....

foo <int> a;

foo <double> b;

Определены статические переменные foo<int>::count и foo<double>::cout.

Аргументы шаблона класса

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

template <class T1,class T2 >

boolean coerce(T1& x, T2 y) {

if(sizeof(x) >= sizeof(y)) x=(T1)y;

else false;

return true;

}

В этом шаблоне функции есть два, возможно различных, типа, описанных как параметры шаблона.

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

template <int n, class T>

class array {

public:

T a[n];

};

array <50,double> x,y;

x=y; // должно работать эффективно

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