Чтение онлайн

ЖАНРЫ

Освой самостоятельно С++ за 21 день.

Либерти Джесс

Шрифт:

Благодаря шаблонам, эта проблема легко решается, а с принятием стандарта ANSI шаблоны стали неотъемлемой частью языка C++, подобно которому они сохраняют тип и очень гибки.

Параметризованные типы

С помошью шаблонов можно "научить" компилятор составлять список элементов любого типа, а не только заданного: PartsList — это список частей, CatsList — это список кошек. Единственное отличие между ними — тип элементов списка. При использовании шаблонов тип элементов списка становится параметром для определения класса.

Обшим компонентом практически

всех библиотек C++ является класс массивов. Как показано на примере с классом List, утомительно и крайне неэффективно создавать один класс массивов для целых, другой — для двойных слов, а еще один — для массива элементов типа Animals. Шаблоны позволяют объявить параметризованный класс массивов, а затем указать, какой тип объекта будет содержаться в каждом экземпляре массива. Заметьте, что стандартная библиотека шаблонов предоставляет стандартизированный набор контейнерных классов, включая массивы, списки и т.д. Сейчас мы выясняем, что нужно для создания вашего собственного класса, только для того, чтобы вы до конца поняли, как работают шаблоны; но в коммерческой программе вы почти стопроцентно будете использовать классы библиотеки STL, а не собственного изготовления.

Создание экземпляра шаблона

Экземпляризация (instantiation) — это операция создания определенного типа из шаблона. Отдельные классы называются экземплярами шаблона.

Параметризованные шаблоны (parameterized templates) предоставляют возможность создания общего класса и для построения конкретных экземпляров передают этому классу в качестве параметров типы данных.

Объявление шаблона

Объявляем параметризованный объект Array (шаблон для массива) путем записи следующих строк:

1: template <class T> // объявляем шаблон и параметр

2: class Array // параметризуемый класс

3: {

4: public:

5: Array;

6: // здесь должно быть полное определение класса

7: };

Ключевое слово template используется в начале каждого объявления и определения класса шаблона. Параметры шаблона располагаются за ключевым словом template. Параметры — это элементы, которые изменяются с каждым экземпляром. Например, в приведенном выше шаблоне массивов будет изменяться тип объектов, сохраняемых в массиве. Один экземпляр шаблона может хранить массив целых чисел, а другой — массив объектов класса Animals.

В этом примере используется ключевое слово class, за которым следует идентификатор Т. Это ключевое слово означает, что параметром является тип. Идентификатор T используется в остальной части определения шаблона, указывая тем самым на параметризованный тип. В одном экземпляре этого класса вместо идентификатора T повсюду будет стоять тип int, а в другом — тип Cat.

Чтобы объявить экземпляры параметризованного класса Array для типов int и Cat, следует написать:

Array<int> anIntArray;

Array<Cat> aCatArray;

Объект anIntArray представляет собой массив целых чисел, а объект aCatArray — массив элементов типа Cat. Теперь вы можете использовать тип Array<int> в любом месте, где обычно указывается какой-либо тип — для возвращаемого функцией значения, для параметра

функции и т.д. В листинге 19.1 содержится полное объявление уже рассмотренного нами шаблона Array.

Примечание:Программа в листинге 19.1 не завершена!

Листинг 19.1. Шаблон класса Array

1: //Листинг 19.1. Шаблон класса массивов

2: #include <iostream.h>

3: const int DefaultSize = 10;

4:

5: template <class T> // объявляем шаблон и параметр

6: class Array // параметризуемый класс

7: {

8: public:

9: // конструкторы

10: Array(int itsSize = DefaultSize);

11: Array(const Array &rhs);

12: ~Array { delete [] pType; }

13:

14: // операторы

15: Array& operator=(const Array&);

16: T& operator[](int offSet) { return pType[offSet]; }

17:

18: // методы доступа

19: int getSize { return itsSize; }

20:

21: private:

22: T *pType;

23: int itsSize;

24: };

Результат:

Результатов нет. Эта программа не завершена.

Анализ: Определение шаблона начинается в строке 5 с ключевого слова template за которым следует параметр. В данном случае параметр идентифицируется как тип за счет использования ключевого слова class, а идентификатор T используется для представления параметризованного типа.

Со строки 6 и до конца определения шаблона (строка 24) вся остальная часть объявления аналогична любому другому объявлению класса. Единственное отличие заключается в том, что везде, где обычно должен стоять тип объекта, используется идентификатор T. Например, можно предположить, что operator[] должен возвращать ссылку на объект в массиве, а на самом деле он объявляется для возврата ссылки на идентификатор типа T.

Если объявлен экземпляр целочисленного массива, перегруженный оператор присваивания этого класса возвратит ссылку на тип integer. А при объявлении экземпляра массива Animal оператор присваивания возвратит ссылку на объект типа Animal.

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

Внутри объявления класса слово Array может использоваться без спецификаторов. В другом месте программы этот класс будет упоминаться как Array<T>. Например, если не поместить конструктор внутри объявления класса, то вы должны записать следующее:

template <class T>

Array<T>::Array(int size):

itsSize = size

{

pType = new T[size];

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

pType[i] = 0;

}

Объявление, занимающее первую строку этого фрагмента кода, устанавливает в качестве параметра тип данных (class T). В таком случае в программе на шаблон можно ссылаться как Array<T>, а объявленную функцию-член вызывать строкой

Array(int size).

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

Поделиться с друзьями: