В рамках данной лабораторной работы Вам предстоит изучить концепцию шаблонов и применить их в своем проекте.
Шаблон — это конструкция, которая создает обычный тип или функцию во время компиляции на основе аргументов, которые пользователь предоставляет для параметров шаблона.
Другими словами, если есть шаблон какой-либо функции или класса, можно получить множество производных функций или классов на его основе. Механизм использования шаблонов очень схож с механизмами наследования и полиморфизма (абстрактные классы), которые Вы изучали ранее.
Для того чтобы объявить шаблон, используется ключевое слово template
:
template<...>
Внутрь <...>
передаются параметры шаблона, которые и будут определять производный от данного шаблона объект. Существует два вида параметров: параметры типа и параметры, не относящиеся к типу. Что это, и как это применять рассмотрим на паре практических примеров.
Допустим, перед нами стоит следующая задача: необходимо написать функцию, принимающую на вход два числа и возвращающую их сумму. Главная проблема заключается в том, что заранее неизвестно, какой тип у суммируемых чисел. Пришлось бы делать перегрузку функции суммы, одну для целочисленных чисел и одну для дробных:
int Sum(int a, int b) {
return a + b;
}
float Sum(float a, float b) {
return a + b;
}
Такая реализация не является оптимальной в большинстве случаев. В случае суммы двух чисел мы можем написать еще одну функцию, это не особая проблема, но что если логика работы функции куда более сложная и на вход она принимает не просто числа, а какой-либо пользовательский тип?
Писать новую перегрузку для функции с появлением каждого нового типа Вам вряд ли захочется. На помощь приходит шаблон:
template<typename T>
T Sum(T a, T b) {
return a + b;
}
Sum(5.5, 3.4)
В данной реализации, T
- это параметр типа, он определяет возвращаемый тип функции Sum
.
Теперь тип возвращаемого значения зависит от типа входных данных, нет необходимости в том, чтобы заранее задавать тип входных данных и тип выходных данных при описании функции. Однако, если в подать на вход такой функции целое число и дробное число - будет ошибка, поскольку параметр типа всего один. Проблема решается путем добавления еще одного параметра:
template<typename T1, typename T2>
T1 Sum(T1 a, T2 b) {
return a + b;
}
Sum(3.4, 6)
Теперь на вход можно подавать разные типы чисел и сумма будет получена в любом случае (тип возвращаемого значения будет зависеть от того, какой тип был у первого параметра функции). Как вы видите, одним шаблоном было покрыто множество реализаций функции суммы двух чисел, что оптимизировало использование и красоту вашего кода. Это довольно простой пример, однако его идея может быть использована в любых масштабах.
Так же как и для функций, для классов также есть возможность использовать шаблоны. Конструкция для создания шаблона схожа с шаблонами для функций:
template<...>
class ClassName {
...
}
Обернем задачу, рассмотренную в шаблонах функций в класс, который будет работать с двумя числами:
template <typename T1, typename T2>
class TwoNumbersWorker {
// Класс работает с двумя числами
public:
TwoNumbersWorker(T1 a, T2 b) {
// В конструкторе происходит инициализация чисел
this->a = a;
this->b = b
}
T1 Sum() {
return a + b;
}
private:
T1 a;
T2 b;
}
Теперь, чтобы создать объект класса TwoNumbersWorker
, нужно указать типы переменных при его создании:
TwoNumbersWorker<int, int> worker(3, 5); // Класс будет работать с целыми числами
std::cout << worker.Sum() << std::endl;
До этого мы рассматривали использование только параметров типа, однако, в качестве параметра шаблона могут выступать и параметры значения.
Рассмотрим такой пример:
template<typename T, size_t L>
class Array
{
T arr[L];
public:
Array() { ... }
};
...
MyArray<int, 10> arr;
Класс Array
является реализацией известного всем нам статического массива. В качестве первого параметра выступает его тип, а вторым параметром является его размер.
На самом деле, Вы уже не раз встречались с шаблонами. Например, при создании вектора, вы указываете его тип, прямо как в примере выше.
std::vector<float> data;
В рамках данной лабораторной работы Вам предстоит шаблонную функцию, вычисляющую среднее арифметическое вектора чисел.
-
Разработайте простое консольное приложение с шаблонной функцией, подсчитывающей среднее арифметическое вектора чисел (в качестве параметра шаблона указывается тип данных вектора).
-
Добавьте в приложение шаблонный класс «Точка» для работы с геометрическими точками на плоскости, с параметризуемым типом координат x и y.
-
Продемонстрируйте работу функции подсчета среднего арифметического для векторов типа int, float и «Точка».
- Что такое шаблон в С++?
- Как применяются шаблоны функции?
- Как применяются шаблоны класса?
- Что, на Ваш взгляд лучше: использование шаблонов или использование наследования?