Шаблоны классов позволяют создавать параметризованные классы.
Параметризованный класс создает семейство родственных классов, которые можно применять к любому типу данных, передаваемому в качестве параметра. Наиболее широкое применение шаблоны находят при создании контейнерных классов. Контейнерным называется класс, который предназначен для хранения каким-либо образом организованных данных и работы с ними.
Преимущество использования шаблонов состоит в том, что как только алгоритм работы с данными определен и отлажен, он может применяться к любым типам данных без переписывания кода.
Параметры шаблона перечисляются через запятую. В качестве параметров могут использоваться типы, шаблоны и переменные.
Типы могут быть как стандартными, так и определенными пользователем. Для их описания используется ключевое слово class. Внутри шаблона параметр типа может применяться в любом месте, где допустимо использовать спецификацию типа, например:
template <class Data> class List{
class Node{
public:
Data d: Node *next: Node *prev;
Node(Data dat = 0){d - dat; next = 0: prev = 0;}
}
}
Класс Data можно рассматривать как формальный параметр, на место которого при компиляции будет подставлен конкретный тип данных.
Область действия параметра шаблона — от точки описания до конца шаблона.
Методы шаблона класса автоматически становятся шаблонами функций. Если метод описывается вне шаблона, его заголовок должен иметь следующие элементы:
Описание параметров шаблона в заголовке функции должно соответствовать шаблону класса, при этом имена параметров могут не совпадать. Проще рассмотреть синтаксис описания методов шаблона на примере:
template <class Data> void List<Data>::print() { /* тело функции */ }
Здесь <class Data>— описание параметра шаблона, void — тип возвращаемого функцией значения, List — имя класса, <Data>— параметр шаблона, print — имя функции без параметров.
Ниже перечислены правила описания шаблонов.
□ Локальные классы не могут содержать шаблоны в качестве своих элементов.
□ Шаблоны методов не могут быть виртуальными.
□ Шаблоны классов могут содержать статические элементы, дружественные функции и классы.
□ Шаблоны могут быть производными как от шаблонов, так и от обычных классов, а также являться базовыми и для шаблонов, и для обычных классов.
□ Внутри шаблона нельзя определять friend-шаблоны.
При определении синтаксиса шаблона было сказано, что в него, кроме типов и шаблонов, могут передаваться переменные. Они могут быть целого или перечисляемого типа, а также указателями или ссылками на объект или функцию. В теле шаблона они могут применяться в любом месте, где допустимо использовать константное выражение.
После создания и отладки шаблоны классов удобно помещать в заголовочные файлы.
Использование шаблонов классов
Чтобы создать при помощи шаблона конкретный объект конкретного класса (этот процесс называется инстанцированием), при описании объекта после имени шаблона в угловых скобках перечисляются его аргументы:
Имя шаблона <аргументы> имя_объекта [(параметры_конструктора)]:
Аргументы должны соответствовать параметрам шаблона. Имя шаблона вместе с аргументами можно воспринимать как уточненное имя класса. Примеры создания объектов по шаблонам, описанным в предыдущем разделе:
List <int> List_int;
List <double> List_double;
List <monstr> Listjnonstr:
Block <char, 128> buf;
Block <monstr. 100> stado;
При использовании параметров шаблона по умолчанию список аргументов может оказаться пустым, при этом угловые скобки опускать нельзя:
template<class Т = char> class String;
String* p;
На месте формальных параметров, являющихся переменными целого типа, должны стоять константные выражения.
После создания объектов с помощью шаблона с ними можно работать так же, как с объектами обычных классов.
Для упрощения использования шаблонов классов можно применить переименование типов с помощью typedef:
typedef List <double> Ldbl;
Ldbl List_double;
Специализация шаблонов классов
Каждая версия класса или функции, создаваемая по шаблону, содержит одинаковый базовый код; изменяется только то, что связано с параметрами шаблона. При этом эффективность работы версий, создаваемых для различных типов данных, может сильно различаться.
Если для какого-либо типа данных существует более эффективный код, можно либо предусмотреть для этого типа специальную реализацию отдельных методов, либо полностью переопределить (специализировать) шаблон класса.
Для специализации метода требуется определить вариант его кода, указав в заголовке конкретный тип данных.
Достоинства и недостатки шаблонов
Шаблоны представляют собой мощное и эффективное средство обращения с различными типами данных, которое можно назвать параметрическим полиморфизмом, а также обеспечивают безопасное использование типов, в отличие от макросов препроцессора. Однако следует иметь в виду, что программа, использующая шаблоны, содержит полный код для каждого порожденного типа, что может увеличить размер исполняемого файла. Кроме того, с некоторыми типами данных шаблоны могут работать не так эффективно, как с другими. В этом случае имеет смысл использовать специализацию шаблона.
Стандартная библиотека С++ предоставляет большой набор шаблонов для различных способов организации хранения и обработки данных.