Определение шаблона
Шаблоны функций
Шаблоны позволяют создавать функции, которые могут обрабатывать разнотипные данные.
В перегрузке функций для каждой сигнатуры определяется своя функция с одинаковым именем.
Шаблон семейства функций определяется один раз, но это определение параметризуется.
Как правило, параметризуются типы любых параметров, тип возвращаемого функцией значения и т. д.
Определение состоит из заголовка шаблона, в котором указаны параметры шаблона и определения функции, в которомтип возвращаемого результата и типы любых параметров обозначаются именами параметров шаблона, введенных в заголовке.
Параметры шаблона могут использоваться и в теле функции для обозначения типов локальных объектов функции.
template < список параметров шаблона>
список параметров: class имя1, class имя2, …
пример:
template<class T>
void swap(T&x, T&y)
{ T z = x;
x= y;
y =z;}
При наличие предложения:
…double a = 6.9, b = 4.66; swap(a,b);
Сформируется и выполнится функция
void swap(double&x, double&y)
{ double z = x;
x= y;
y =z;}
1)Имена параметров шаблона должны быть уникальными в определении шаблона;
2) список параметров не может быть пустым;
3) может быть несколько параметров
template<class T1,classT2,classT3>
имена должны быть все разные, и обязательно перед каждым слово class
4)все параметры шаблона обязательно должны быть использованы в спецификации параметров функции
template<class T1,classT2,classT3>
T3 f (T1 a, T2 b) { T3 c;... } // ошибка!
Классы и шаблоны
Шаблон позволяет создавать семейство родственных классов
Определение шаблона семейства классов
template<список параметров шаблона> определение класса
Имя класса в определении класса – это не имя отдельного класса, а параметризованное имя семейства классов
Рассмотрим на примере класса векторов. Данными этого класса являются массив координат, какой бы тип не имели элементы массива. Тип элемента задается как параметр шаблона. И для любого типа элементов определяются базовые операции.
Определение шаблона класса (как и функции) может быть только глобальным
// шаблон векторов
template<class T> // Т – параметр шаблона
class Vector // Vector - имя семейства классов
{T* data; // данные класса
int size; // размер пространства
public:
Vector(int); // конструктор
~Vector () { delete [ ]data; } // деструктор
// перегрузка операции “ [ ]”
T& operator [ ] (int i) { return data[i];}
friend ostream & operator << (ostream&, Vector <T>);
};
template<class T> // внешнее определение конструктора шаблона
Vector <T>:: Vector(int n)
{data = new T[n];
size =n;}
// определение перегрузки операции <<
ostream & operator << (ostream& out, Vector <T> X)
{ out<<endl;
for(int i=0;i<X.size; i++)
out<<X[i]<<" "; return out;}
Теперь можно объявлять объекты конкретных классов, порожденных из шаблона
Имя параметризованного класса(шаблона) < фактические параметры шаблона>
имя объекта (параметры конструктора);
т.е. имя конкретного класса будет:
Имя параметризованного класса(шаблона) < фактические параметры шаблона>
Vector<char> A(5); // вектор – массив из пяти значений типа char
// здесь Vector <char> - имя класса
void main()
{clrscr();
// статическте объекты:
Vector<int> X(5);
Vector <char> C(5);
// динамический объект:
Vector<int>*p= new Vector<int> (10);
// заполнение элементов значениями и вывод элементов вектора,
// используя перегруженную операцию []
for(int j =0; j<10; j++)
{(*p)[j]= j; cout<< (*p)[j]<<" ";}
cout<<"\n\n";
for (int i=0; i<5; i++)
{X[i]=i; C[i]='A'+i;
cout<<X[i]<<" " << C[i];
}
// вывод объекта X используя перегруженную операцию <<
cout<< X;
}
Шаблоны классов
Ранее были рассмотрены шаблоны функций, с помощью которых можно отделить алгоритм от конкретных типов данных, с которыми он работает, передавая тип в качестве параметра.
Шаблоны классов предоставляют аналогичную возможность, позволяя создавать параметризованные классы.
Параметризованный класс создает семейство родственных классов, которые можно применять к любому типу данных, передаваемому в качестве параметра.
Наиболее широкое применение шаблоны находят при создании контейнерных классов.
Контейнерным называется класс, который предназначен для хранения каким-либо образом организованных данных и работы с ними.
Стандартная библиотека C++ содержит множество контейнерных классов для организации структур данных различного вида.
Преимущество использования шаблонов состоит в том, что как только алгоритм работы с данными определен и отлажен, он может применяться к любым типам данных без переписывания кода.
Шаблоны классов, так же как и шаблоны функций, поддерживают в C++ парадигму обобщенного программирования, то есть программирования с использованием типов в качестве параметров.
Механизм шаблонов в C++ допускает применение абстрактного типа в качестве параметра при определении класса или функции.
После того как шаблон класса определен, он может использоваться для определения конкретных классов.
Процесс генерации компилятором определения конкретного класса по шаблону класса и аргументам шаблона называется инстанцированием шаблона (template instantiation).
Рассмотрим, например, точку на плоскости. Для ее представления ранее мы разработали класс point, в котором положение точки задавалось двумя координатами х и у — полями типа double. Представим теперь, что в другом приложении требуется задавать точки для целочисленной системы координат, то есть использовать поля типа int. Можно вообразить себе системы, в которых координаты точки имеют тип short или unsigned char.
Так что же — определять каждый раз новый класс point для каждой из этих задач? Бьерна Страуструпа очень раздражала такая перспектива, и он добавил в C++ поддержку шаблонов классов.
Определение шаблона класса
Определение шаблонного (обобщенного, родового) класса имеет вид:
template <параметры_шаблона> class имя_класса { /*... */ };
Например, определение шаблонного класса point будет выглядеть следующим образом:
template <class Т> class point {
public:
point (T _х = 0, T _у = 0): х(_х), у(_у) {}
void Show() {
cout << " (" << x << ", " << у << ")" << endl;}
private: