- •11. Инкапсуляция
- •12. Полиморфизм
- •13. Наследование
- •Управление доступом
- •Элементы класса
- •Элементы данных
- •Элементы функции
- •15. Перегрузка функций
- •16. Конструкторы и деструкторы Конструктор
- •Деструктор
- •17. Параметризированные конструкторы
- •18. Дружественные функции
- •19. Inline-функции
- •20. Передача объектов в функции
- •21. Возвращение объектов функциями
- •22. Массивы объектов
- •23. Указатели на объекты
- •24. Указатель this
- •25. Перегрузка операторов
- •26. Ссылки
- •27. Наследование и спецификаторы доступа
- •28. Конструкторы и деструкторы производных классов
- •29. Множественное наследование. Передача параметров в конструктор базового класса
- •30. Указатели и ссылки на производные типы
- •31. Виртуальные функции
- •32. Чисто виртуальные функции и абстрактные типы
- •33. Раннее и позднее связывание
- •35. Создание собственных операторов вставки и извлечения.
- •36. Форматирование ввода-вывода
- •37. Файловый ввод-вывод
- •38. Чтение и запись в текстовые файлы
- •39. Двоичные файлы
- •40. Функции-шаблоны
- •41. Классы-шаблоны
- •42. Использование пространства имён
- •43. Контейнерные классы
- •46. Основы обработки исключений
- •47. Идентификация типа во время исполнения (rtti)
- •49. Виртуальный базовый класс
40. Функции-шаблоны
Функция-шаблон определяет общий набор операций, который будет применён к данным различных типов. Используя этот механизм, можно применять некоторые общие алгоритмы к широкому кругу данных. Как известно, многие алгоритмы логически одинаковы вне зависимости от типа данных, с которыми они оперируют. Например, алгоритм быстрой сортировки один и тот же и для массива целых чисел и для массива чисел с плавающей точкой. При помощи создания функции-шаблона можно определить сущность алгоритма безотносительно к типу данных. После этого компилятор автоматически генерирует корректный код для того типа данных, для которого создаётся данная конкретная реализация функции на этапе компиляции.
Функции-шаблоны создаются с использованием ключевого слова template (шаблон). Шаблон используется для создания каркаса функции, оставляя компилятору реализацию подробностей. Общая форма функции-шаблона имеет следующий вид:
template<class Т> возвращаемый_тип имя_функции(список параметров)
{
// тело функции
}
Здесь Т является параметром-типом, «держателем места» для имени типа данных, которое используется функцией. Этот параметр-тип может быть использован в определении функции. Он будет автоматически заменён компилятором на фактический тип данных во время создания конкретной версии функции.
Листинг 1
// пример шаблона функции
#include <iostream>
using namespace std;
// шаблон функции
template <class X> void Swap(X &a, X &b)
{
X temp;
temp=a;
a=b;
b=temp;
}
int main()
{
int i=10, j=20;
double x=10.1, y=23.3;
char a='x', b='z';
cout<<"Original i, j: "<< i << " " << j << "\n";
cout<<"Original x, y: "<< x << " " << y << "\n";
cout<<"Original a, b: "<< a << " " << b << "\n";
Swap(i, j);
Swap(x, y);
Swap(a, b);
cout<<"Swapped i, j: " << i << " " << j << "\n";
cout<<"Swapped x, y: " << x << " " << y << "\n";
cout<<"Swapped a, b: " << a << " " << b << "\n";
return 0;
}
Можно определить несколько типов-шаблонов данных в инструкции template, используя список с запятыми в качестве разделителя. Например, следующая программа создаёт функцию-шаблон имеющую два типа-шаблона.
Листинг 2
#include <iostream>
using namespace std;
template <class type1, class type2> void myfunc(type1 x, type2 y)
{
cout << x << " " << y << endl;
}
int main()
{
myfunc(10, "hi");
myfunc(0.23, 10L);
return 0;
}
Явная перегрузка функций-шаблонов
Хотя функция-шаблон перегружает себя по мере необходимости, также можно перегрузить её явным образом. Если перегружается функция – шаблон, то перегруженная функция переопределяет функцию шаблон для того конкретного набора типов параметров, для которых создаётся перегруженная функция. В качестве примера рассмотрим следующую версию функции swap().
Листинг 3
// перегрузка функции-шаблона
#include <iostream>
using namespace std;
// шаблон функции
template <class X> void Swap(X &a, X &b)
{
X temp;
temp=a;
a=b;
b=temp;
}
// отдельная версия Swap()
void Swap(int &a, int &b)
{
int temp;
temp=a;
a=b;
b=temp;
cout << "Inside overloaded Swap().\n";
}
int main()
{
int i=10, j=20;
double x=10.1, y=23.3;
char a='x', b='z';
cout << "Original i, j: " << i << " " << j << "\n";
cout << "Original x, y: " << x << " " << y << "\n";
cout << "Original a, b: " << a << " " << b << "\n";
Swap(i, j);
Swap(x, y);
Swap(a, b);
cout << "Swapped i, j: " << i << " " << j << "\n";
cout << "Swapped x, y: " << x << " " << y << "\n";
cout << "Swapped a, b: " << a << " " << b << "\n";
return 0;
}
Ограничения на функции-шаблоны
Функции-шаблоны сходны с перегруженными функциями, за исключением того, что они более ограничены. Для перегруженных функций можно выполнять различные действия в теле каждой функции. Для функции-шаблона необходимо выполнять одни и те же общие действия, и только тип данных может быть различным.
Пример (перегруженные функции не могут быть заменены на функцию-шаблон)
#include <iostream>
#include <math.h>
using namespace std;
void myfunc(int i)
{
cout << "value is: " << i << "\n";
}
void myfunc(double d)
{
double intpart;
double fracpart;
fracpart = modf(d, &intpart);
cout << "fractional part: " << fracpart;
cout << "\n";
cout << "Integer part: " << intpart;
}
int main()
{
myfunc(1);
myfunc(12.2);
return 0;
}
Другим ограничением на классы-шаблоны является то, что виртуальная функция не может быть функцией-шаблоном.