Шаблоны классов
-
Шаблоны классов - это объявления классов, предваряемые спецификацией template.
-
Шаблоны классов автоматически расширяются компилятором до полных определений классов так, как это необходимо.
-
Не могут быть вложены в другие классы (в отличие от других классов).
// Объявить класс Stack, который представляет собой стек для любых типов.
template <class T> class Stack {
T *v; // указатель на некоторый тип T
int size,top;
public:
Stack(int s); ~Stack(); // и т.д.
};
Stack <int> i; // Стек для int
Stack <char*> cp; // Стек для char*
-
Шаблоны классов могут иметь нетипированные (или только нетипированные) параметры. Значения, указанные для этих параметров, должны быть константными выражениями.
// Передать размер как параметр шаблона
template <class T,int size> class Stack {
T v[size]; // Массив элементов типа T.
int top;
public:
Stack():top(-1) {}//...
};
Stack <int,20> tiny;
Stack <int,500> huge;
Хотя стеки tiny и huge и хранят тип int, но все же это различные типы, поскольку они имеют разный размер стека. Это можно проиллюстрировать тем, что указатель Stack<int,20> - это не то же самое , что указатель на Stack<int,500>.
Stack<int,20> *ps20=&tiny; // Правильно
Stack<int,500> *ps500=&tiny; // Ошибка
-
Шаблоны классов могут быть порождены как от нешаблонных классов, так и от классов шаблонов. А также могут порождать как нешаблонные классы, так и классы-шаблоны. Когда от класса-шаблона порождается нешаблонный класс, всем параметрам класса-шаблона должны быть присвоены некоторые “реальные” значения. В примере это int.
class A { /*...*/ }
template <class T> class B: public A { /*...*/ }
template <class T> class C: public B { /*...*/ }
class D: public C <int> { /*...*/ }
-
Шаблоны классов для определенных типов могут быть перекрыты для того, чтобы выполнять (или не выполнять) какие-либо действия, которые шаблоны классов не выполняют (или выполняют).
// Объявим свой собственный стек для char*
class Stack<char*> {
char * *v; // указатель на char*
int size,top; //...
};
-
Шаблоны классов могут также быть классами-структурами или классами-объединениями.
Статические данные-члены
-
Статические данные-члены разделяются всеми объектами класса для каждого конкретного экземпляра класса-шаблона
-
Статические данные-члены определяются в области видимости файла (как и все статические поля), когда определение предваряется спецификацией template
template <class T> class C {
static int i; // Обычное статическое поле
static T t; // Параметризованное
};
template<class T> int C<T>::i; // Определить в области видимости файла
template<class T> T C<T>::t;
С<char> c; // Имеет int C::i и char C::t;
C<float> f; // Имеет int C::i и float C::t;
Шаблоны функций-членов
-
Определяются вне объявлений классов, к которым они принадлежат, при помощи спецификации template
template<class T> void Stack<T>::Push(const T &el) {
if(top==size-1) error(“stack overflow”);
else v[++top]=el;
}
-
Шаблоны функций-членов для определенных типов могут быть перекрыты для того, чтобы выполнять (или не выполнять) какие-либо действия, которые шаблоны функций-членов не выполняют (или выполняют).
void Satck<char*>::Push(const char*& cpr) { /* выполнить нечто особенное */}
Дружественные функции
-
Дружественные функции для каждого типа T могут быть друзьями всех классов типа Т. Это обычные дружественные функции.
-
Дружественные функции для типа Т могут быть друзьями класса типа Т.
-
Дружественные функции могут предваряться спецификацией template. Для типов T и U, функции-шаблоны типа U являются дружественными функциями каждому классу типа Т.
template<class T> class Person {
freind void Pet();
friend void Spouse(Person &);
template<class U> freind void Coworker(U&);
};
void Pet() { /*...*/ } // Обычная функция
template<class T>void Spouse(Person &p) {}
template<class U>void Coworker(U &u) {]
Здесь Pet() - функция, дружественная Person<T> для каждого типа T.
Person<int>
Pet() Person<char>
....
Person<float>
Для любого типа T, скажем int, Spouse(Person<int>&) - функция, дружественная Person<int>, но не Person<char>, или любому другому типу.
Spouse(Person<int>&) Person<int>
Spouse(Person<char>&) Person<char>
... ...
Spouse(Person<float>&) Person<float>
Coworker(U &) - функция, дружественная Person<T>, для любого типа T и любого типа U.
Coworker(int&) Person<int>
Coworker(char&) Peson<char>
... ...
Coworker(float&) Person<float>
-
Дружественные функции могут быть функциями-членами другого класса.
template<class T> class Perosn {
freind void Family::Sibilding();
freind void Acquaintance::Casual(Person &);
template<class U>friend void Neighbor<U>::Nextdoor(U&);
};
Здесь Family::Sibilding() - фукнция, дружественная Person<T>, для каждого типа T. Для любого типа Т, скажем для int, Acquaintance<int>::Causal(Person<int>&) - функция, дружественная Person<int>, но не Person<char>, или любому другому типу. Neighbor<U>::NextDoor(U&) -функция, дружественная Person<T>, для любого типа U.
-
Дружкственные функции могут быть объявлены для всего класса.
template<class T>class Person {
friend class Family;
freind class Acquaintance;
template<class U> freind class Neighbor;
};
Здесь для каждого типа Т все функции-члены класса Family - это функции, дружественные Person<T>. Для любого типа, скажем для int, все функции-члены класса Acquaintance<int> являются друзьями Person<int>, но не Person<char>, или любого другого типа. Для каждого типа Т и каждого типа U все фунции-члены Nieghbor<U> являются друзьями Person<T>.
-
Дружественные функции могут также быть друзьями нешаблонных классов.