Литмир - Электронная Библиотека
A
A

19.3.2. Обобщенное программирование

 

Программирование. Принципы и практика использования C++ Исправленное издание - _002.png
 Шаблоны — это основа для обобщенного программирования на языке С++. По существу, простейшее определение обобщенного программирования на языке С++ — это программирование с помощью шаблонов. Хотя, конечно, это определение носит слишком упрощенный характер. Не следует давать определения фундаментальных понятий программирования в терминах конструкций языка программирования. Эти конструкции существуют для того, чтобы поддерживать технологии программирования, а не наоборот. Как и большинство широко известных понятий, обобщенное программирование имеет несколько определений. Мы считаем наиболее полезным самое простое из них.

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

 

Программирование. Принципы и практика использования C++ Исправленное издание - _002.png
 Например, элементы вектора должны иметь тип, который можно копировать (с помощью копирующего конструктора и копирующего присваивания). В главах 20-21 будут представлены шаблоны, у которых аргументами являются арифметические операции. Когда мы производим параметризацию класса, мы получаем шаблонный класс (class template), который часто называют также параметризованным типом (parameterized type) или параметризованным классом (parameterized class). Когда мы производим параметризацию функции, мы получаем шаблонную функцию (function template), которую часто называют параметризованной функцией (parameterized function), а иногда алгоритмом (algorithm). По этой причине обобщенное программирование иногда называют алгоритмически ориентированным программированием (algorithm-oriented programming); в этом случае основное внимание при проектировании переносится на алгоритмы, а не на используемые типы.

 

Программирование. Принципы и практика использования C++ Исправленное издание - _002.png
 Поскольку понятие параметризованных типов играет такую важную роль в программировании, мы попытаемся в дальнейшем немного разобраться в этой запутанной терминологии. Это даст нам возможность избежать недоразумений, когда мы встретим знакомые понятия в другом контексте.

 

Программирование. Принципы и практика использования C++ Исправленное издание - _002.png
 Данную форму обобщенного программирования, основанную на явных шаблонных параметрах, часто называют параметрическим полиморфизмом (parametric polymorphism). В противоположность ей полиморфизм, возникающий благодаря иерархии классов и виртуальным функциям, называют специальным полиморфизмом (ad hoc polymorphism), а соответствующий стиль — ориентированным программированием (см. разделы 14.3-14.4). Причина, по которой оба стиля программирования называют полиморфизмом (polymorphism), заключается в том, что каждый из них дает программисту возможность создавать много версий одного и того же понятия с помощью единого интерфейса. Полиморфизм по-гречески означает “много форм”. Таким образом, вы можете манипулировать разными типами с помощью общего интерфейса. В примерах, посвященных классу
Shape
, рассмотренных в главах 16–19, мы буквально работали с разными формами (классами
Text
,
Circle
и
Polygon
) с помощью интерфейса, определенного классом
Shape
. Используя класс
vector
, мы фактически работаем со многими векторами (например,
vector<int>
,
vector<double>
и
vector<Shape*>
) с помощью интерфейса, определенного шаблонным классом
vector
.

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

v.push_back(x); // записать x в вектор v

s.draw(); // нарисовать фигуру s

Для вызова

v.push_back(x)
компилятор определит тип элементов в объекте
v
и применит соответствующую функцию
push_back()
, а для вызова
s.draw()
он неявно вызовет некую функцию
draw()
(с помощью таблицы виртуальных функций, связанной с объектом
s
; см. раздел 14.3.1). Это дает объектно-ориентированному программированию свободу, которой лишено обобщенное программирование, но в то же время это делает обычное обобщенное программирование более систематическим, понятным и эффективным (благодаря прилагательным “специальный” и “параметрический”).

 

Программирование. Принципы и практика использования C++ Исправленное издание - _002.png
 Подведем итоги.

Обобщенное программирование поддерживается шаблонами, основываясь на решениях, принятых на этапе компиляции

Объектно-ориентированное программирование поддерживается иерархиями классов и виртуальными функциями, основываясь на решениях, принятых на этапе выполнения программы.

Сочетание этих стилей программирования вполне возможно и полезно. Рассмотрим пример.

void draw_all(vector<Shape*>& v)

{

  for (int i=0; i<v.size(); ++i) v[i]–>draw();

}

Здесь мы вызываем виртуальную функцию (

draw()
) из базового класса (
Shape
) с помощью другой виртуальной функции — это определенно объектно-ориентированное программирование. Однако указатели
Shape*
хранятся в объекте класса
vector
, который является параметризованным типом, значит, мы одновременно применяем (простое) обобщенное программирование.

 

Программирование. Принципы и практика использования C++ Исправленное издание - _001.png
 Но довольно философии. Для чего же на самом деле используются шаблоны?

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

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

• Используйте шаблоны, когда гибкость сочетания информации, поступающей от разных типов, играет важную роль (например, при работе со стандартной библиотекой языка C++; эта тема будет обсуждаться в главах 20 и 21).

 

Программирование. Принципы и практика использования C++ Исправленное издание - _003.png
 Шаблоны имеют много полезных свойств, таких как высокая гибкость и почти оптимальная производительность, но, к сожалению, они не идеальны. Как всегда, преимуществам сопутствуют недостатки. Основным недостатком шаблонов является то, что гибкость и высокая производительность достигаются за счет плохого разделения между “внутренностью” шаблона (его определением) и его интерфейсом (объявлением). Это проявляется в плохой диагностике ошибок, особенно плохими являются сообщения об ошибках. Иногда эти сообщения об ошибках в процессе компиляции выдаются намного позже, чем следовало бы.

258
{"b":"847443","o":1}