Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Lutsik_Yu_A_Obektno_orientir_programmir_na_yaz.pdf
Скачиваний:
63
Добавлен:
11.05.2015
Размер:
4.33 Mб
Скачать

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

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

#include <iostream> using namespace std; #include <string.h>

 

template <class T1,class T2>

 

 

 

 

Р

 

T1 sm(T1 a,T2 b)

// описание шаблона

 

 

{ return (T1)(a+b);

 

 

 

 

 

 

// функции c двумя параметрами

 

}

 

 

 

 

 

 

 

 

И

 

template <class T1,class T2,class T3>

 

 

 

 

У

 

 

T1 sm(T1 a,T2 b,T3 c)

 

 

 

 

 

// описание шаблона функции

 

 

{ return (T1)(a+b+c);

// функции c тремя параметрами

 

}

 

 

 

 

 

 

Г

 

 

 

 

 

 

 

 

 

Б

 

 

 

 

int main()

 

 

 

 

 

 

 

 

{cout<<"вызов функции sm(int,int)

= "<<sm(4,6)<<endl;

 

 

cout<<"вызов функции sm(int,int,int)а= "<<sm(4,6,1)<<endl;

 

 

cout<<"вызов функции sm(int,double) = "<<sm(5,3)<<endl;

 

 

 

 

 

 

к

 

 

 

 

 

 

cout<<"вызов функции sm(double,int,short)= " <<

 

 

 

 

sm(.4,6,(short)1)<<endl;е

 

 

 

 

 

 

// cout<<sm("я изучаю","язык С++")<<endl; error cannot add two pointers

 

}

return 0;

 

т

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

о

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Резу ьтат работы программы будет иметь вид:

 

 

 

вызов функ

 

sm(int,int)

 

=

10

 

 

 

 

 

 

ции

 

 

=

11

 

 

 

 

вызов функции sm(int,int,int)

 

 

 

 

 

л

 

 

 

=

5

 

 

 

 

вызов функции sm(int,double)

 

 

 

 

вызов функции sm(double,int,short)=

7.4

 

 

 

 

б

 

 

 

 

 

 

 

 

 

 

В программе описана перегруженная функция sm(), первый экземпляр ко-

торойимеет 2, а второй 3 параметра.

Тип формальных параметров функции оп-

Б

 

 

 

 

 

 

 

 

 

 

 

ределяется компилятором при каждой встрече вызова функции типом ее факти- ческих параметров. Компилятор заменяет параметры T1,T2 (при вызове функ- ции с двумя параметрами) или T1,T2,T3 (с тремя параметрами) на типы переда- ваемых в функцию значений. После этого полученная шаблонная функция ком- пилируется. Используемые в функциях типы Т1, Т2, Т3 заданы как параметры для шаблона функции с помощью выражения template <class T1,class T2> или template <class T1,class T2,class T3>.

133

Имя каждого формального параметра заголовка шаблона может исполь- зоваться в заголовке только один раз. Одно и то же имя формального параметра шаблона может использоваться в нескольких заголовках шаблонов.

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

шем случае:

 

 

 

 

 

 

 

 

 

 

 

 

char *sm(char *a,char *b)

 

 

//

явное описание функции объединения

{ char *tmp=a;

 

 

 

 

//

двух строк

 

 

 

Р

 

a=new char[strlen(a)+strlen(b)+1];

 

 

 

 

 

 

strcpy(a,tmp);

 

 

 

 

 

 

 

 

 

 

 

strcat(a,b);

 

 

 

 

 

 

 

 

 

 

 

}

return a;

 

 

 

 

 

 

 

 

 

 

И

 

 

 

 

 

 

 

 

 

 

 

Добавление в main() инструкции, например,

 

У

 

cout<<sm("я изучаю"," язык С++")<<endl;

 

 

Г

 

 

приведет к выводу кроме указанных выше сообщения:

 

 

я изучаю язык С++

 

 

 

 

 

 

 

 

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

функций с одинаковым числом аргументов.

а

 

 

 

 

template <class T1,class T2>

 

 

 

 

 

 

 

T1 sm(T1 a,T2 b)

 

 

 

// описа кшаблона первой

 

 

 

{ return (T1)(a+b);

 

 

// функции c двумя параметрами

 

 

}

 

 

 

 

 

 

ние

 

 

 

 

 

template <class T1,class T2>

 

 

 

 

 

 

 

 

T1 sm(T2 a,T1 b)

 

 

т// писание шаблона второй

 

 

 

{ return (T1)(a+b);

 

 

// функции c двумя параметрами

 

 

}

 

 

 

о

 

 

 

 

 

 

 

 

 

и

 

 

 

 

 

 

 

 

 

int main()

 

 

 

 

 

 

 

 

 

 

{ sm(1.,2) //лerror 'sm' : none of 2 overload have a best conversion

 

 

 

// 'sm' : ambiguous call to overloaded function

 

 

 

 

б

 

 

 

 

 

 

 

 

 

 

 

 

return 0;

 

 

 

 

 

 

 

 

 

 

 

 

}

и

 

 

 

 

 

 

 

 

 

 

 

 

В этом случае компилятор должен сгенерировать оба экземпляра шаб-

лонныхБфункций. Возникает неоднозначность: какую из двух шаблонных функ-

ций требуется выполнить.

 

 

 

 

 

 

 

 

 

 

Шаблон функции может быть перегружен также, если описать другую

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

Только при обращении к функции с аргументами конкретного типа происходит генерация конкретной функции.

134

6.4. Совместное использование шаблонов и наследования

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

- шаблон класса может быть порожден от обычного класса; - шаблонный класс может быть производным от шаблонного класса;

- обычный класс может быть производным от шаблона класса.

 

Ниже приведен пример простой программы, демонстрирующей наследо-

вание

 

 

 

 

 

 

 

 

 

ИР

 

using namespace std;

 

 

 

 

 

template <class T>

 

 

 

 

У

 

class vect

 

 

 

 

 

Г

 

 

 

 

// класс-вектор

 

 

{protected:

 

 

 

 

 

Б

 

 

 

 

T *ms;

 

 

 

// массив-вектор

 

 

 

 

int size;

 

 

 

// размерность массива-вектора

 

public:

 

 

 

 

 

 

 

 

 

 

vect(int n) : size(n)

 

 

 

// конструктор

 

 

 

{ ms=new T[size];}

 

а// деструктор

 

 

 

 

 

 

е

 

 

 

~vect(){delete [] ms;}

 

 

 

 

T &operator[](const intкind) // доопределение операции []

 

 

 

 

 

т

 

 

 

 

 

 

 

{ if((ind>0) && (ind<size)) return ms[ind];

 

 

 

 

else return ms[0];

 

 

 

 

 

 

 

}

о

 

 

 

 

 

 

};

 

и

 

 

 

 

 

 

 

 

 

л

 

 

 

 

 

 

 

 

template <class T>

 

 

 

 

 

 

class oper : public vect<T> // класс операций над вектором

 

{ public:

 

 

 

 

 

 

 

и

oper(int n): vect<T>(n) {}

 

// конструктор

~oper(){}

 

 

 

 

// деструктор

 

Б

бvoid print()

 

 

 

 

// функция вывода содержимого вектора

 

 

 

{ for(int i=0;i<size;i++)

 

 

 

 

 

 

cout<<ms[i]<<' ';

 

 

 

 

 

 

 

 

cout<<endl;

 

 

 

 

 

 

};

 

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

int main()

 

 

 

 

 

 

 

 

{ oper <int> v_i(4);

 

 

//

int-вектор

 

 

 

oper <double> v_d(4);

 

//

double-вектор

 

 

v_i[0]=5; v_i[1]=3;

v_i[2]=2; v_i[3]=4; // инициализация int

 

 

 

 

 

 

 

 

 

 

135

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]