Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Конспект лекций -=Вычислительная техника и прог...docx
Скачиваний:
11
Добавлен:
01.05.2025
Размер:
2 Мб
Скачать
☆

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

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

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

Если соответствие на одном этапе получается более чем одним способом, то возникает неоднозначность вызова.

Избежать неоднозначности можно используя явное преобразование типов аргументов.

Примеры:

/* 1) Перегрузка функций */

…

// Имеется 4-е варианта функции, определяющей наибольшее знач-е

int max(int , int) ; // (1) наибольшее из двух целых

char* max(char* , char*) ; // (2) наиболее длинная из двух строк

int max(int , char*) ; // (3) наибольшее из 1-го и длины 2-го

int max(char* , int) ; // (4) наибольшее из длины 1-го и 2-го

…

void func(int a , int b , char* c , char* d)

{ cout<<max(a , b)<<max(с , d)<<max(a , c)<< max(d , b);

} // (1) (2) (3) (4)

…

В примере:

— выбор варианта функции max осуществляется на этапе компиляции программы в соответствии с типом фактических параметров (аргументов);

— в данном примере все четыре варианта функции вызываются последовательно.

/* 2) Перегрузка функций (неоднозначность) */

#include <iostream.h>

float f(float i)

{

cout<< ''Function float f(float i)'' << endl ;

return i ;

}

double f(double i)

{

cout<< ''Function double f(float i)'' << endl ;

return i+2 ;

}

int main()

{

float x=10.09 ;

double y=10.09 ;

cout<< f(x) << endl ; // вызывается f (float)

cout<< f(y) << endl ; // вызывается f (double)

cout<< f(10) << endl ; // возникает неоднозначность

// преобразования 10 во float

// или double

return 0 ;

}

В примере:

При вызове функции f(10) возникает неоднозначность и компилятор выдает ошибку. Для устранения неоднозначности в примере требуется '10’ преобразовать явным образом к требуемому типу f(float(10)) или f(double(10)).

Правила описания перегруженных функций:

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

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

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

int и const int

или

int и int & .

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

Шаблоны функций предназначены:

— для повышения эффективности программы, содержащей однотипную обработку данных различных типов, например, сортировка чисел типа int и double;

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

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

Вызов функции, который использует конкретный тип данных, приводит к созданию компилятором кода для соответствующей версии функции. Этот процесс называется созданием экземпляра (instantiation) шаблона.

Формат определения шаблона функции:

template <class список_типов> имя_функции (список параметров)

{

/* тело функции */

}

Здесь:

список_типов — список типов, которые определяются при вызове функции;

список параметров — список параметров, передаваемых в функцию.

Примечания:

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

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

template <class TypeA , class TypeB>

void f(TypeA x, TypeB y, int i) { … }

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

4. Типы параметров, передаваемых в функцию при вызове шаблона функции, могут определяться автоматически. А могут быть установлены принудительно («вручную»).

Пример:

/* Автоматическое определение типа параметров функции */

#include <iostream.h>

template <class Type> void SortVybor(Type *b, int n);

main() { const int n=20;

int i, b[n] ;

double a[n] ;

for (i=1; i<n; i++) cin>>b[i] ;

SortVybor(b, n) ; //сорт-ка целочисленного массива

for (i=1; i<n; i++) cin>>a[i] ;

SortVybor(a, n) ; // сорт-ка вещественного массива

return 0;

}

/* Шаблон функции сортировки методом прямого выбора: */

template <class Type> void SortVybor (Type *b, int n)

{

Type a; // буфер для обмена элементов

int imin ; // номер наименьш. эл-та в исходн. массиве

for (int i=0 ; i<n–1 ; i++)

{ imin=i ;

for (int j=i+1 ; j<n ; j++) // выбор

if (b[j]<b[imin]) imin=j ; // наименьшего

a=b[i] ; b[i]=b[imin] ; b[imin]=a ; // и обмен

}

}

/* Принудительное определение типа параметров функции */

// Шаблон функции определен как

template <class X, class Y, class Z> void Func(Y, Z) ;

// Вызовы функции:

Func <int, char*, float> (“University”, 3.3); //1

Func <int, char*> (“University”, 3.3); //2

Func <int> (“University”, 3.3); //3

Func (“University”, 3.3); //4

Здесь:

//1 — все определено программистом;

//2 — принудительно определены X и Y, параметр Z определен автоматически как double;

//3 — принудительно определен X, автоматически определены Y — char*, Z — double;

//4 — ОШИБКА: невозможно определить тип X