При наследовании класса на основе шаблона нам надо указать значения для параметров шаблона базового класса. И в данном случае мы можем также и производный класс определить как шаблон, и использовать его параметры при установке базового класса:
#include <iostream>
#include <string>
template <typename T>
class Person {
public:
Person(T id, std::string name) : id{id}, name{name} { }
void print() const
{
std::cout << "Id: " << id << "\tName: " << name << std::endl;
}
protected:
T id;
std::string name;
};
template <typename T>
class Employee: public Person<T> {
public:
Employee(T id, std::string name, std::string company) : Person<T>{id, name}, company{company} { }
void print() const
{
Person<T>::print();
std::cout << Person<T>::name << " works in " << company << std::endl;
}
private:
std::string company;
};
int main()
{
Employee<unsigned> bob{123, "Bob", "Google"};
bob.print(); // Id: 123 Name: Bob
// Bob works in Google
}
В данном случае в начале определен шаблон базового класса Person, который использует параметр шаблона T для установки типа для переменной id. Далее определен шаблон класс Employee, который наследуется от класса Person:
template <typename T> class Employee: public Person<T>
Таким образом, для базового класса в качестве параметра шаблона будет использоваться то значение, которое определяется шаблоном Employee.
При этом чтобы обратиться к функциональности базового класса, необходимо использовать выражение Person<T> (то есть указывать значение для параметра шаблона Person):
Person<T>{id, name} // вызов конструктора
Person<T>::print(); // вызов функции print
Person<T>::name // обращение к переменной name базового класса Person
Далее в программе мы можем типизировать объекты Employee определенным типом, и этот тип будет применяться для фукциональности базового класса:
Employee<unsigned> bob{123, "Bob", "Google"};
Другой вариант наследования состоит в том, что на этапе наследования мы явным образом устанавливаем для базового класса используемые типы:
#include <iostream>
#include <string>
template <typename T>
class Person {
public:
Person(T id, std::string name) : id{id}, name{name} { }
void print() const
{
std::cout << "Id: " << id << "\tName: " << name << std::endl;
}
protected:
T id;
std::string name;
};
class Employee: public Person<unsigned> {
public:
Employee(unsigned id, std::string name, std::string company) : Person{id, name}, company{company} { }
void print() const
{
Person::print();
std::cout << name << " works in " << company << std::endl;
}
private:
std::string company;
};
int main()
{
Employee bob{123, "Bob", "Google"};
bob.print(); // Id: 123 Name: Bob
// Bob works in Google
}
В данном случае класс Employee представляет обычный класс, который наследуется от типа Person<unsigned>. То есть теперь для функционала базового класса
параметр T будет представлять тип unsigned.