Skip to content

Latest commit

 

History

History
167 lines (114 loc) · 9.32 KB

File metadata and controls

167 lines (114 loc) · 9.32 KB

Объектно-ориентированное программирование

Лабораторная работа №8. Шаблоны


В рамках данной лабораторной работы Вам предстоит изучить концепцию шаблонов и применить их в своем проекте.

Теоретическая справка

Что такое шаблон в С++?

Шаблон — это конструкция, которая создает обычный тип или функцию во время компиляции на основе аргументов, которые пользователь предоставляет для параметров шаблона.

Другими словами, если есть шаблон какой-либо функции или класса, можно получить множество производных функций или классов на его основе. Механизм использования шаблонов очень схож с механизмами наследования и полиморфизма (абстрактные классы), которые Вы изучали ранее.

Для того чтобы объявить шаблон, используется ключевое слово 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;

Задание

В рамках данной лабораторной работы Вам предстоит шаблонную функцию, вычисляющую среднее арифметическое вектора чисел.

Ход работы

  1. Разработайте простое консольное приложение с шаблонной функцией, подсчитывающей среднее арифметическое вектора чисел (в качестве параметра шаблона указывается тип данных вектора).

  2. Добавьте в приложение шаблонный класс «Точка» для работы с геометрическими точками на плоскости, с параметризуемым типом координат x и y.

  3. Продемонстрируйте работу функции подсчета среднего арифметического для векторов типа int, float и «Точка».

Контрольные вопросы

  1. Что такое шаблон в С++?
  2. Как применяются шаблоны функции?
  3. Как применяются шаблоны класса?
  4. Что, на Ваш взгляд лучше: использование шаблонов или использование наследования?