Шаблон класса дает обобщенное определение семейства классов, использующее произвольные типы или константы. Шаблон определяет элементы данных и элементы-функции класса. После определения шаблона классавы можете предписать компилятору генерировать на его основе новый класс для конкретного типа или константы. Синтаксис шаблона классаимеет следующий вид:
template <список_аргументов_шаблона> class имя_класса { //тело класса };
За ключевым словом template следуют один или несколько аргументов, заключенных в угловые скобки и отделяемых друг от друга запятыми. Каждый аргумент является либо именем типа, за которым следует идентификатор, либо ключевым словом class, за которым следует идентификатор, обозначающий параметризованный тип. Затем следует определение класса. Оно аналогично определению обычного класса, за исключением того, что использует список аргументов шаблона. Функции-элементы шаблона класса могут быть как встроенными, так и определяться вне тела класса. В этом случае заголовок функции имеет следующий формат:
template <список_аргументов_шаблона> возвр_тип имя_класса <арг_шаблона> :: имя_функции(параметры…) { // тело функции } Например:
#include <stdlib.h> const size_t def_size = 10; template <class T> class TStack { public: TStack(size_t size = def_size) { numItems = 0; items = new T[size]; } ~TStack() {delete[] items;}; void push(T t); T pop(); protected: int numItems; T *items; }; template <class T> void TStack<T>::push(T t) { items[numItems++] = t; } template <class T> T TStack<T>::pop() { return items[--numItems]; } Чтобы создать представитель шаблонного класса, можно просто указать имя шаблона со списком аргументов, заключенным в угловые скобки, в качестве спецификатора типа. Создав представитель шаблонного класса, можно обращаться с ним точно так же, как с принадлежащим обычному классу. Например, продолжая предыдущую запись:
int main(void) { TStack<int> StackOfInt(10); // – из 10 элементов StackOfInt.push(11); StackOfInt.push(12); StackOfInt.push(13); cout << “Было помещено” << StackOfInt.pop()<<’,’<< StackOfInt.pop()<<’,’<< StackOfInt.pop(); // – из 20 элементов TStack<double> StackOfDouble(20); StackOfDouble.push(1.1); StackOfDouble.push(1.2); StackOfDouble.push(1.3); cout << “Было помещено” << StackOfDouble.pop()<<’,’<< StackOfDouble.pop()<<’,’<< StackOfDouble.pop(); return 0; }
ЧТО ТАКОЕ ЧИСТО ВИРТУАЛЬНЫЕ ФУНКЦИИ
Как вы уже знаете, для создания полиморфного объекта ваши программы определяют один или несколько методов базового класса как виртуальные функции. Производный класс может определить свою собственную функцию, которая выполняется вместо виртуальной функции базового класса, или использовать базовую функцию (другими словами, производный класс может и не определять свой собственный метод). В зависимости от программы иногда не имеет смысла определять виртуальную функцию в базовом классе. Например, объекты производных типов могут настолько сильно отличаться, что им не нужно будет использовать метод базового класса. В таких случаях вместо определения операторов для виртуальной функции базового класса ваши программы могут создать чисто виртуальную функцию, которая не содержит операторов.
Для создания чисто виртуальной функции ваша программа указывает прототип функции, но не указывает ее операторы. Вместо них программа присваивает функции значение ноль, как показано ниже:
Каждый производный класс, определенный в вашей программе, должен определить свою функцию вместо чисто виртуальной функции базового класса. Если производный класс опустит определение функции для чисто виртуальной функции, компилятор C++ сообщит о синтаксических ошибках.