Шаблоны классов / обобщенные классы.
Аналогично шаблонных функций в C++ можно создавать шаблонные классы, т.е. классы, которые конструируются на этапе компиляции.
template<typename T>
class MyClass
{
public:
MyClass(T value) {this->value=value;}
void PrintValue() {cout<<value<<endl;}
T getValue(){return this->value;}
private:
T value;
};
В функции main:
MyClass<int> c_Int(10);
MyClass<string> c_String("Hello");
c_Int.PrintValue();
c_String.PrintValue();
Используя шаблон класса MyClass мы создаем 2 объекта класса c_Int и c_String, работающие с функционалом шаблонного класса, но разными типами данных.
По сути на этапе компиляции вместо T в шаблоне класса подставляется значение, указанное в скобках <int> или <string> и тд.
Типы передаваемых данных (typename T) могут быть любыми, главное чтобы методы шаблонного класса поддерживали работу с ними, например мы можем передать в шаблон свой собственный класс, но в данном случае оператор вывода на консоль << в нем должен быть перегружен.
Как и в случае шаблонных функций мы можем использовать более 1 обобщенного типа переменной, для этого в шаблоне функции пишем:
template<typename T1, typename T2 >
class MyClass {//code};
В функции main вызываем например так:
MyClass<int, string> c_T2(…);
Примечание 1:
template<typename T> можно также записать как template<class T> разницы нет, но лично мне больше нравится typename.
Примечание 2:
#include <typeinfo> //иногда работает и без нее
typeid(value).name – функция выдает данные о типе typename T
cout<< typeid(value).name<<endl;
Примечание 3:
При вынесении методов/конструкторов/деструктора из класса необходимо указывать, что класс шаблонный
template<typename T>
MyClass<T>::Metod(){}
Наследование от шаблонного класса с «избавлением» от шаблонности:
class Student : public Person<int>
{
//code
};
Наследование от шаблонного класса с сохранением шаблонности:
template<typename T>
class Student : public Person<T>
{
//code
};
Специализация шаблона класса
Иногда возникает ситуация когда для отдельных типов данных нужна отдельная обработка в шаблоне класса, поэтому можно шаблон специализировать (по сути перегрузить)
Рассмотрим на примере:
template<typename T>
class MyClass
{
public:
MyClass(T value) {this->value=value;}
void PrintValue() {cout<<value<<endl;}
private:
T value;
};
напишем специализацию для типа int:
template <>
class MyClass<int>
{
public:
MyClass(int value) {this->value=value;}
void PrintValue() {cout<<value+1<<endl;}
void PrintValue_x2() {cout<<value*2<<endl;}
private:
int value;
тогда в main:
MyClass<int> c_Int(10);
MyClass<string> c_String("Hello");
c_Int.PrintValue(); //выведет 11
c_Int.PrintValue_x2(); //выведет 20
c_String.PrintValue();
Теперь при создании шаблона класса с переменной типа int будет вызываться переопределенный шаблон, соответственно будут доступны все методы и поля переопределенного шаблона.