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

309

Глава 21. Шаблоны, исключения

21.1.Шаблоны

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

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

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

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

template <class T> void swap(T *x, T *y)

{T tmp; tmp = *x; *x = *y; *y = tmp;}

Здесь T – формальный параметр шаблона, обозначаемый ключевым словом class. Параметры шаблона заключаются в угловые скобки < и >. Теперь функцию swap можно использовать для аргументов любых типов. Например,

long k = 4, d = 8; swap(&k, &d);

Компилятор автоматически сформирует определение функции:

void swap(long *x, long *y)

{long tmp; tmp = *x; *x = *y; *y = tmp;}

Имя типа в шаблоне является параметром, вместо которого можно подставлять любые типы.

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

template <class T, int n>

310

Шаблон может иметь несколько параметров, например,

template <class T1, class T2>

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

Программа 65. Объявление и определение шаблона функции

В данной программе сначала объявляется шаблон функции count0 для подсчета числа нулевых элементов массива, затем дается его определение.

// Файл TmplFunc.cpp

 

 

template<class D>

// Объявление шаблона функции,

int count0(D *x, int n);

// подсчитывающей число нулей в массиве

#include <iostream.h>

 

 

int main()

// Использование шаблона

{

 

 

int x[] = {1, 2, 0, 3, 0, 4, 0, 5, 3, 3, 1, 0, 0};

// Массив из 13 int

double y[] = {0.0, 1.0, 2.0, 0.0, 2.3};

// Массив из 5 double

cout << "Число нулей в x: " << count0(x, 13) << endl; cout << "Число нулей в y: " << count0(y, 5) << endl; cin.get();

return 0;

}

 

// Определение шаблона функции

 

template<class T>

 

int count0(T *x, int n)

// x – массив элементов

{

// n – число элементов в массиве

int k = 0;

 

for(int i = 0; i < n; i++)

 

if(int(x[i]) == 0)

 

k++;

 

return k;

 

}

 

Программа выводит:

Число нулей в x: 5 Число нулей в y: 2

311

21.3. Классы и шаблоны

Шаблон семейства классов определяется инструкцией:

template <СПИСОК_ПАРАМЕТРОВ_ШАБЛОНА> ОПРЕДЕЛЕНИЕ_КЛАССА

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

Программа 66. Шаблон классов векторов

В данной программе определен шаблон классов Vect для моделирования векторов, элементы которых могут иметь любой тип.

// Файл TmplVect.cpp

 

template <class T>

// T – параметр шаблона

class Vect{

 

T *v;

// Одномерный массив из элементов типа T

int n;

// Размер массива

public:

 

Vect(int);

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

~Vect()

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

{ delete[] v;}

 

T& operator[](int i)

// Доступ к элементу вектора

{ return v[i]; }

 

};

 

При определении функций-членов шаблона классов следует повторить объявление параметра шаблона с помощью template. Определение конструктора имеет вид:

template <class T> Vect <T>::Vect(int k)

{ n = k; v = new T[n]; }

После введения шаблона классов можно определять конкретные объекты конкретных классов.

#include <iostream.h>

 

void main()

 

{

 

Vect <int> X(5);

// Целочисленный вектор из 5 элементов

Vect<char> S(5);

// Символьный вектор

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

// Заполнение векторов

X[i] = i;

 

312

S[i] = 'A' + i;

}

for(i = 0; i < 5; i++) // Вывод веторов cout << " " << X[i] << ' '<< S[i];

cin.get();

}

Приведенная программа выводит:

0 A 1 B 2 C 3 D 4 E

Значением параметра шаблона может быть стандартный тип (int, double,...) или тип, определённый пользователем.

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

Программа 67. Шаблон классов динамических массивов

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

// Файл TmplDArr.cpp

 

#include <stdlib.h>

// Для rand()

#include <time.h>

 

#include <iostream>

 

#include<Windows.h>

// Для функции CharToOem

char Buff[500];

// Буфер для преобразования русских букв

char* Rus(char* in)

// Функция для преобразования русских букв

{

 

CharToOem(in, Buff);

// Функция CharToOem преобразует строку in

return Buff;

// в строку Buff, используя кодировку DOS

}

using namespace std;

template <class T, int size = 64> // 64 – значение по умолчанию для size

class DynArr {

// Шаблон классов динамических массивов

T* data;

// Массив элементов

int n;

// Количество элементов

public:

 

DynArr()

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

{ data = new T[n = size]; }

 

~DynArr()

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

{delete[] data;}

 

T& operator[](int i)

// Доступ к элементу

{ return data[i];}

 

 

 

313

int SizeArr()

 

// Размер массива

{return n;}

 

 

T GetMax();

// Возвращает значение максимального элемента

};

 

 

// Определение функции-члена шаблона классов

template <class D, int sz>

// Имена параметров шаблона в определении

D DynArr<D, sz>::GetMax()

// могут отличатся от их имен в объявлении

{

 

 

D max = data[0]; for(int i = 1; i < n; i++)

if(data[i] > max) max = data[i];

return max;

}

В главной функции создаются два динамических массива: x с размером по умолчанию и y заданного размера. Массивы заполняются случайными числами, генерируемыми функцией int rand(void). Для того, чтобы при каждом запуске программы генерировались различные последовательности чисел, вызывается функция

void srand(unsigned seed);

Ее аргумент задает начальную точку в последовательности псевдослучайных чисел, генерируемых rand. Для получения значения seed использована объявленная в time.h функция

time_t time(time_t *timer);

возвращающая количество секунд, прошедших от полуночи 1 января 1970 г. Это значение записывается также по адресу timer или игнорируется, если timer=NULL. Тип time_t – это новое обозначение для long, введенное с помощью typedef.

Обработка созданных массивов состоит в том, что выводятся значения их максимальных элементов.

int main()

 

{

 

srand(unsigned(time(NULL)));

// Инициализация датчика сл. чисел

DynArr<double> x;

// Массив x из 64 double

DynArr<int, 20> y;

// Массив y из 20 int

int i;

 

for(i = 0; i < x.SizeArr(); i++)

// Заполнение массива x

x[i] = rand();

 

cout << Rus("Количество элементов в x: ") << x.SizeArr(); cout << Rus(", максимальное из x: ") << x.GetMax() << endl;