Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ТП лекции Раздел 4.doc
Скачиваний:
16
Добавлен:
28.09.2019
Размер:
2.56 Mб
Скачать

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

Шаблон классов (class template) в руководствах программиста иногда называет­ся generic class или class generator – генератор классов. Шаблон действительно помогает компилятору сгенерировать определение конкретного класса по образу и подобию заданной схемы. Разработчики компилятора C++ различают два термина: class template и template class. Первый означает абстрактный шаблон классов, а второй — одно из его конкретных воплощений. Пользователь может сам создать template class для какого-то типа данных. В этом случае созданный класс отменяет (overrides) ав­томатическую генерацию класса по шаблону для этого типа данных. Рассмотрим стандартный пример, иллюстрирующий использование шаблона для автомати­ческого создания классов, которые реализуют функционирование абстрактного типа данных Вектор линейного пространства. Элементами вектора могут быть объекты различной природы. В примере создаются векторы: целых, веществен­ных и объектов некоторого класса Circle (вектор окружностей). Для вектора из элементов любого типа тела методов шаблона одинаковы, поэтому и есть смысл объединить их в шаблоне.

template <class T> class Vector // Шаблон классов «Вектор линейного пространства»

{

Т *data ; // Указатель начала массива компонентов

int size; // Размер массива

public:

Vector(int);

~Vector() { deleted data; }

T& operator [](int i) { return data[i]; }

};

// Внешняя реализация тела конструктора

template <class T> Vector<T>:: Vector (int n)

{data = new T[n];}

class Circle // Глобальное определение класса

{

int х. у, r;

public:

Circle () {х=у=r=0;}

Circle (int a, int b, int с) {x=a; y=b; r=c;}

double area () { return 3.14159*r*r; }

};

void main()

Vector <int> x(5); // Генерируется вектор целых

int i;

for (i=0; i<5; ++i) x[I]=I;// Инициализация

for (i=0; i<5: ++i) cout«x[i]«' '; // Вывод

Vector <float> y(10); // Генерируется вектор вещественных

for (i=0; i<10: ++i) // Инициализация

y[i] = float(i);

for (i=0; i<10: ++i)

cout«y[i]«' '; //Вывод // Генерируется вектор объектов класса Circle Vector <Circle> z(4); for (i=0: i<4; ++i) //Инициализация

z[i] = Circle(i+100,i+100,i+20); for (i=0; i<4; ++i) //Вывод

cout« z[i].area() « ' ';

}

Обратите внимание на синтаксис внешней реализации тела конструктора шаб­лона классов. Vector<T> — это имя шаблона. Vector(int n) — имя метода шаблона (конструктор). При использовании шаблона для генерации конкретного вектора объектов необходимо задать в угловых скобках тип данных (известный к этому моменту и видимый в этой области программы). Использование шаблона всегда предполагает наличие описателя типа при имени класса (Vector <type>). Имя Vector теперь не может быть использовано без указания конкретного типа эле­ментов. В рассмотренном примере операция [] определена в шаблоне как общая для всех типов Т, однако метод area() определен только для объектов класса Circle, и он применяется к объекту z[i] класса Circle, вектор из четырех элементов которого автоматически создается компилятором при объявлении Vector <Circle> z(4);.

Если для какого-то типа переменных автоматически сгенерированный по шаблону класс не подходит, то его следует описать явно. Созданный таким образом класс (template class) отменяет автоматическое создание класса по шаблону только для этого типа. Например, пусть для вновь созданного типа:

typedef int (*Tfunc)(int);

(указатель на функцию, возвращающую значение типа int и требующую аргу­мент типа int) мы не хотим использовать class template Vector, но хотим создать вектор указателей на функции, работающий иначе. С этой целью мы явно опи­сываем конкретное воплощение (template class) класса Vector для типа Tfunc:

class Vector <Tfunc>

{

Tfunc *data;

int size;

public:

Vector (int, Tfunc);

-Vector () { delete [] data; }

Tfunc& operator [] (int i) { return data[i]; }

Vector <Tfunc> :: Vector (int n, Tfunc f)

{

size = n;

data = new Tfunc[n];

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

data[i]=f;

}

Здесь отличие от шаблона состоит в том, что конструктор класса Vector <Tfunc> имеет теперь два параметра, а не один, как было в шаблоне. Кроме этого, весь вектор указателей на функции инициализируется адресом одной и той же функ­ции, поданной на вход конструктора. Для проверки функционирования вектора из элементов типа Tfunc следует создать какую-нибудь тестовую функцию нуж­ного типа, а в функцию main добавить манипуляции с реальным вектором типа Tfunc. Например:

int func (int j)

{

int i=j*2;

cout<<”\n func:”<< j<<”=”<<i;

return i ;

}

Vector <Tfunc> ff (5, func);

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

cout « ff[i](i) « ' ' ;

Обратите внимание на то, что при создании вектора ff (5, func); из пяти ука­зателей на функции вторым параметром передается имя функции, а следова­тельно, ее адрес, инициализирующий все элементы массива f f типа Vector <Tfunc>.