Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Определение шаблонов функций




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

Вспомним параграф «Перегруженные функции» гл. 2, в котором указывалось, что для использования одной и той же функции с различными типами данных нужно определить отдельную перегруженную версию этой функции для каждого типа. Если требуется функция, возвращающая абсолютную величину значения как типа int, так и типа double, то нужно написать две перегруженные функции, приведенные в гл. 2 в качестве примера.

int Abs(int N){ return N < 0? -N: N;}double Abs (double N){ return N < 0.0? -N: N; }

Используя шаблон языка C++, можно создать единственное определение, автоматически обрабатывающее значения типа int, double или любого другого подходящего типа. Такой шаблон выглядит следующим образом.

template <class T> T Abs (T N) { return N < 0? -N: N; }

В этом определении идентификатор т является параметром типа (type parameter). Он переопределяет тип переменной или константы, передаваемой при вызове функции. Если программа вызывает функцию Abs и передает ей значение типа int, например,

cout << "absolute value of -5 is " << Abs (-5);

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

int Abs (int N) { return N < 0? -N: N;}

Аналогично, если программа вызывает функцию Abs и передает ей значение типа double, например,

double D = -2.54;cout << "absolute value of D is " << Abs (D);

то компилятор сгенерирует версию функции, в которой тип идентификатора T будет заменен double, и добавит в программу вызов данной функции. Эта версия функции эквивалентна следующей.

double Abs (double N) { return N < 0? -N: N; }

Таким же образом компилятор генерирует дополнительные версии функции для каждого вызова, в котором указывается новый числовой тип данных, например short или float. Генерация новой версии функции называется созданием экземпляра (instantiating) шаблона функции.

При определении шаблона нужно использовать спецификаторы template и class вместе с угловыми скобками, как показано в приведенном выше примере. Для параметра типа T можно использовать любой корректный идентификатор имени, а в угловые скобки можно включать несколько параметров типа.

Примечание

Не следует в шаблоне функции путать понятия параметр функции и параметр типа. Параметр функции представляет собой значение, передаваемое в функцию при выполнении программы. Параметр типа, напротив, задает тип аргумента, передаваемого в функцию, и полностью обрабатывается при компиляции. Обратите внимание: в контексте определения шаблона спецификатор class в угловых скобках ссылается не на конкретный тип данных class, а на любой тип данных, фактически передаваемых при вызове (как встроенный, так и определенный программистом тип данных).

Само по себе определение шаблона не вызывает генерацию кода компилятором. Компилятор генерирует код функции только при ее фактическом вызове. Поэтому он не может обнаружить ошибки в тексте шаблона функции до вызова этой функции в исходном файле. Первый же вызов с определенным типом данных приводит к генерации компилятором кода соответствующей версии функции. Последующие вызовы с указанием тех же типов данных не сгенерируют дополнительные копии функции, а лишь вызовут ее первоначальную копию. Однако компилятор сгенерирует новую версию функции, если тип параметра не совпадет в точности с типом в предыдущем вызове. Рассмотрим случай, когда программа передает в шаблон функции параметр типа long, а компилятор генерирует соответствующую версию функции. Если затем программа передаст параметр типа int, компилятор сгенерирует полностью новую версию функции для обработки типа int. Он не будет выполнять стандартное преобразование int в long для использования кода первой версии функции.

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

Еще один пример шаблона функции.

template <class Т> Т Мах (Т А, Т В) { return А > В? А: В;}

Этот шаблон генерирует функции, возвращающие большее из двух значений одинакового типа. Так как оба параметра определены как имеющие тип идентификатора T, в вызове функции оба передаваемых параметра должны быть только одного типа. В противном случае компилятор не определит, какой тип соответствует параметру идентификатора T – тип первого или второго параметра. (Вспомните: значение параметра T определяется типом передаваемых параметров.) Таким образом, допустимы такие вызовы функции.

cout << "The greater of 10 and 5 is " << Max (10, 5) << '\n'; cout << "The greater of 'A' and 'M' is " << Max ('A', 'M') << '\n'; cout << "The greater of 2.5 and 2.6 is " << Max (2.5, 2.6) << '\n';

А следующий вызов является недопустимым.

cout << "The greater of 15.5 and 10 is " << Max (15.5, 10) << '\n'; // ОШИБКА!

Обратите внимание: компилятор не преобразует второй параметр int в double для приведения типов, хотя это преобразование является стандартным.

Чтобы передавать параметры различных типов, нужно определить шаблон функции.

template <class Type1, class Type2 > Type1 Max (Type1 A, Type2 B) { return Type1 (A > В? A: B); }

В данном шаблоне Type1 обозначает тип значения, передаваемого в качестве первого, а Туре2 – второго параметров. Для новой версии шаблона следующий оператор является допустимым и печатает значение 15.5.

cout << "The greater of 15.5 and 10 is " << Max (15.5, 10) << '\n'; // теперь допустимо

Заметьте: в новом определении Мах параметр Type1 появляется внутри тела функции, где он используется для приведения возвращаемого значения (если это необходимо) к типу первого параметра функции.

return Type1 (А > В? А: В);

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

Так как возвращаемое значение преобразуется к типу первого параметра, то при изменении порядка параметров предыдущего примера

cout << "The greater of 15.5 and 10 is " << Max (10, 15.5) << '\n';

полученный результат сравнения (15.5) будет округлен и составит 15.

Отметим: каждый параметр типа, встречающийся внутри символов «<» и «>», должен также появляться в списке параметров функции. Следовательно, следующее определение шаблона не допустимо:

// ОШИБКА: список параметров функции должен // включать Туре2 как параметр типа:template <class Type1, class Type2> Type1 Max (Type1 A, Type1 B){ return A > В? A: B;}

При таком определении компилятор, встретив вызов функции, не сможет определить значение идентификатора Туре2. Это – ошибка, даже если идентификатор Туре2 не использован.




Поделиться с друзьями:


Дата добавления: 2014-01-05; Просмотров: 396; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.013 сек.