Выбрать главу

Вернемся к примеру из предыдущего параграфа. Представим, что мы поразмыслили и решили, что в будущем для нас может стать актуальным быстродействие и необходимость реализации C++ API. Сводим эти критерии в таблицу с инверсной шкалой, считаем, что важность этих критериев одинакова. Подсчитываем сумму (Табл. 11).

Табл. 11. Интегральные оценки с инверсной шкалой

Получившиеся результаты суммируем с результатами, полученными с использованием обычной шкалы (Табл. 12).

Табл. 12. Поправки с учетом инверсной шкалы

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

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

3.4. Итоги

Сравнительный анализ реализаций обратных вызовов необходим для выбора наилучшей в конкретной ситуации. Методика анализа включает в себя выбор объектов, определение критериев сравнения, построение матрицы соответствия, выбор оптимального решения.

Качественный анализ используется, если необходимо выбрать реализацию, оптимальную по какому-нибудь единственному критерию. Если у нас имеется несколько критериев, то необходим количественный анализ, в качестве которого применяется метод интегральных оценок.

Рассмотренные методики подходят не только для исследования обратных вызовов, их можно применять в любых других случаях, когда необходим выбор оптимального архитектурного решения из множества возможных.

4. Обратные вызовы и шаблоны

4.1. Общие понятия шаблонов

Шаблоны в C++ являются инструментом, реализующим параметрический полиморфизм, что означает возможность построения единого (обобщенного) кода для различных типов данных16. В таком коде не задаются конкретные типы, а вводятся параметры, в которые затем подставляется нужный тип данных. Чтобы код работал корректно, типы должны удовлетворять некоторым соглашениям, или, другими словами, поддерживать определенный интерфейс.

Обобщенный код – это код, реализующий заданную функциональность без привязки к типам данных.

Шаблоны объявляются ключевым словом template, после которого в угловых скобках перечисляются параметры. Параметрами шаблона могут быть как типы данных, так и значения.

Пример объявления шаблона:

template SomeTemplate<typename type, int value>

Здесь объявлен шаблон с одним параметром-типом type и параметром-значением value.

Параметрам шаблона, как типам, так и значениям, могут быть назначены значения по умолчанию:

template SomeTemplate<typename type = SomeStruct(), int value = 0>

После объявления шаблона следует код шаблона, в качестве которого выступает функция либо класс. В этом коде вместо имен типов и числовых значений можно подставлять имена параметров. Конкретные типы и значения, подставляемые в эти параметры, станут известны после инстанциирования шаблона, под которым понимается объявление экземпляра шаблона с заданными типами.

Инстанциирование шаблона – это объявление экземпляра шаблона с заданными типами.

Инстанциирование шаблона может быть явным и неявным. При явном инстанциировании типы параметров шаблона объявляются, а при неявном – выводятся, исходя из типов входных аргументов. Пример объявления шаблонов и их инстанциирование представлены в Листинг 23.

Листинг 23. Объявление шаблона и его инстанциирование

template<typename type, int size = 1>  // (1)

class StaticArray

{

public:

  type array[size];

};

template <typename TYPE>          // (2)

TYPE Sum(TYPE s2, TYPE s3)

{

  return s2 + s3;

}

int main()

{

  StaticArray<int, 1> someArray;  // (3)

  int a = 0; double x = 8;

  Sum(a, a);                      // (4)

  Sum<double> (a, x);             // (5)

}

вернуться

16

В противоположность полиморфизму подтипов, который подразумевает исполнение потенциально разного кода для каждого типа или подтипа. В C++ полиморфизм подтипов реализуется с помощью наследования и виртуальных функций.

Термины «параметрический полиморфизм» и «полиморфизм подтипов» больше характерны для академической литературы, в C++ обычно используются их эквиваленты «статический полиморфизм» и «динамический полиморфизм». С точки зрения теории, такая терминология не совсем корректна, потому что она скорее отражает не сущность полиморфизма, а способ его реализации в конкретном языке программирования. Тем не менее, в C++ эти термины прижились.