Перегрузка функций. Шаблоны функций 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Перегрузка функций. Шаблоны функций



Краткая теория

Перегрузка функций

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

Рассмотрим создание перегруженных функций на примере.

 

Пример. Перегрузка функций

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

#include <iostream>

#include <math.h>

using namespace std;

//объявим две структуры для хранения информации о координатах точек

//в декартовой системе

struct cartesian{

double x, y;

};

//и в полярной системе координат

struct polar{

double r, pi;

};

//теперь определим перегружаемую функцию,

//принимающую координаты двух точек через полярные координаты

double len(polar a, polar b)

{

cout << "Считаем расстояние через полярные координаты" << endl;

return sqrt(pow(a.r, 2) + pow(b.r, 2) - 2*a.r*b.r*cos(a.pi - b.pi));

}

//а затем принимающую координаты двух точек через декартовы координаты

double len(cartesian x, cartesian y)

{

cout << "Считаем расстояние через декартовы координаты" << endl;

return sqrt(pow(y.x - x.x, 2)+pow(y.y - x.y, 2));

}

//будем считать, что при передаче четырех параметров

//передаются декартовы координаты двух точек

double len(double x1, double y1, double x2, double y2)

{

cout << "Считаем расстояние через декартовы \

координаты с 4-мя параметрами" << endl;

return sqrt(pow(x2 - x1, 2)+pow(y2 - y1, 2));

}

 

void main(int argc, char* argv[])

{

setlocale(LC_ALL, "Russian");

const double PI = 3.14159;

cartesian a = {3, 0},

b = {1, 1};

polar c = {1.41, PI/4},

d = {3.1, 0.95};

double x1 = 1.4, y1 = 2.5,

x2 = 2.1, y2 = 3.7;

cout << len(a, b) << endl;

cout << len(c, d) << endl;

cout << len(x1, y1, x2, y2) << endl;

}

 

Результат работы:

 

Считаем расстояние через декартовы координаты

2.23607

Считаем расстояние через полярные координаты

1.7246

Считаем расстояние через декартовы координаты с 4-мя параметрами

1.38924

 

Рекурсивные функции

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

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

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

Рекурсия

В математике часто встречается рекурсивное определение функции. Значение функции от аргумента и определяется через одно или несколько предыдущих значений n-1, n-2,... Классический пример — определение факториала: 0!=1, n!= n(n-1)\.

По этому определению 4! = 4 • 3!, но 3! = 3 • 2!, а 2! = 2 • 1!, 1! = 1 • 0! и мы дошли до конца рекурсии, раскрыли "матрешку" вложенных друг в друга определений. После этого движемся в обратном порядке, выполняя умножения: 1! = 1 • 1 = 1, 2! = 2 • 1 = 2, 3! = 3 • 2 = 6, наконец, 4! = 4 • 3 = 24.

Язык С допускает вызов функции внутри самой функции, поэтому рекур­сию легко запрограммировать:

int fact(int n){

if (n < 0) return -1; /* Неправильный аргумент. */

if (n == 0) return 1;

return n * fact(n -1);

}

Конечно, вычислять рекурсивно такие простые функции не стоит, рекурсия требует большого расхода ресурсов. Здесь достаточно простого цикла:

int fact(int n){

if (n < 0) return -1; /* Ошибка. */

int k, f = 1;

for (k = 2; k <= n; k++) f *= k;

return f;

}

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

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

 

Шаблоны функций

Цель введения шаблонов функций – автоматизация создания функций, которые могут обрабатывать разнотипные данные. В отличие от механизма перегрузки, когда для каждой сигнатуры определяется своя функция, шаблон семейства функций определяется один раз. Шаблон располагается перед main.

 

template <class ttype>

 

ttype имя_функции (список_формальных_параметров)

{

тело функции

}

 

Здесь ttype – любой корректный идентификатор, который автоматически заменяется компилятором на любой стандартный тип.

 

Пример. Шаблон функции для нахождения максимального элемента массива

#include <iostream>

#include <math.h>

using namespace std;

template <class array_type>

array_type max(array_type *a, const int N)

{

array_type m = a[0];

for (int i = 1; i < N; i++)

if (a[i] > m)

{

m = a[i];

}

return m;

}

 

int main(int argc, char* argv[])

{

setlocale(LC_ALL, "Russian");

 

double a[] = {2.5, 8.3, 6};

int b[] = {3, 5, -1, 2};

char c[] = {'A', 'b', 'Z', 'r'};

cout << max(a, sizeof(a)/sizeof(a[0])) << endl;

cout << max(b, sizeof(b)/sizeof(b[0])) << endl;

cout << max(c, sizeof(c)/sizeof(c[0])) << endl;

return 0;

}

 

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

Основные свойства параметров шаблона:

1. Имена параметров шаблона должны быть уникальными во всем определении шаблона.

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

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

Допустимый заголовок шаблона:

 

template <class type1, class type2>

 

Соответственно, неверен заголовок:

 

template <class type1, type2, type3>

 

4. Недопустимо использовать в заголовке шаблона параметры с одинаковыми именами, т.е. ошибочен такой заголовок:

 

template <class type1, class type1, class type1>

 



Поделиться:


Последнее изменение этой страницы: 2016-12-11; просмотров: 668; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.223.108.186 (0.016 с.)