Новости

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

Работа добавлена:






Перегрузка функций в C++ на http://mirrorref.ru

Каждая программа наC++ – это совокупностьфункций, каждая из которых должна быть определена или описана до её использования в конкретном модуле программы. Рассмотрим более сложные примеры использования функций.

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

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

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

Небольшие перегруженные функции удобно применять при отладке программ.

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

voidprint(char*str,constinti,constintj)

{

cout<<str<<'|'<<oct<<setw(4)<<i<<'|'<<setw(4)<<j

<<'|'<<endl;

}

voidprint(floatarray[],constintn)

{

cout<<"Массив:"<<endl;

cout.setf(ios::fixed);

cout.precision(2);

for(inti=0;i<n;i++)

{

cout<<array[i]<<" ";

if((i+1)%4==0)cout<<endl;

}

cout<<endl;

}

voidprint(Manm)

{

cout.setf(ios::fixed);

cout.precision(2);

cout<<setw(40)<<m.name<<' '<<m.birthday<<' '

<<m.pay<<endl;

}

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

Во второй функции для вывода вещественных значений по четыре числа на строке задается вид вывода с фиксированной точкой и точностью в два десятичных знака после запятой. Для этого используются методы установки флаговsetf, установки точностиprecision и константаfixed, определенная в классеios. Точность касается только вещественных чисел, ее действие продолжается до следующей установки. Третья функция выводит поля знакомой нам по шестому семинару структуры так, чтобы они не склеивались между собой. Манипуляторsetw устанавливает ширину следующего за ним поля. Это приведет к тому, что фамилии будут выведены с отступом от края экрана. Вызов этих функций в программе может выглядеть, например, так:

print("Послецикла ",i,j);

print(a,n);

print(m);

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

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

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

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

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

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

#include "stdafx.h"

#include <iostream>

#include <math.h>

usingnamespacestd;

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

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

structcartesian{

doublex,y;

};

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

structpolar{

doubler,pi;

};

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

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

doublelen(polara,polarb)

{

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

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

}

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

doublelen(cartesianx,cartesiany)

{

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

returnsqrt(pow(y.x-x.x,2)+pow(y.y-x.y,2));

}

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

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

doublelen(doublex1,doubley1,doublex2,doubley2)

{

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

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

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

}

voidmain(intargc,char*argv[])

{

setlocale(LC_ALL,"Russian");

constdoublePI=3.14159;

cartesiana={3,0},

b={1,1};

polarc={1.41,PI/4},

d={3.1,0.95};

doublex1=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

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

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

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

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

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

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

template<class ttype>

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

{

  тело функции

}

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

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

#include "stdafx.h"

#include <iostream>

#include <math.h>

usingnamespacestd;

template<classarray_type>

array_typemax(array_type*a,constintN)

{

array_typem=a[0];

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

if(a[i]>m)

{

m=a[i];

}

returnm;

}

intmain(intargc,char*argv[])

{

setlocale(LC_ALL,"Russian");

doublea[]={2.5,8.3,6};

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

charc[]={'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;

return0;

}

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

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

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

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

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

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

template<classtype1,classtype2>

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

template<classtype1, type2, type3>

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

template<classtype1,classtype1, classtype1>

2.4 Функции с переменным количеством параметров

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

тип имя(список_явных_параметров,...);

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

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

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

В обоих случаях переход от одного фактического параметра к другому выполняется с помощью указателей (с использованием адресной арифметики).

#include "stdafx.h"

#include <iostream>

usingnamespacestd;

longsumma(intk,...)

{

int*pik=&k;

longtotal=0;

for(;k;k--)

total+=*(++pik);

returntotal;

}

intmain(intargc,char*argv[])

{

setlocale(LC_ALL,"Russian");

cout<<"\n summa(2, 6, 4) = "<<summa(2,6,4);

cout<<"\n summa(6, 1, 2, 3, 4, 5, 6) ="<<

summa(6,1,2,3,4,5,6);

return0;

}

Результат

summa(2, 6, 4)=10

summa(6, 1, 2, 3, 4, 5, 6)=21

Особенность этой программы, что указательpik может работать только с целочисленными фактическими параметрами.

#include "stdafx.h"

#include <iostream>

usingnamespacestd;

doubleprod(doublearg,...)

{

doubleresult=1.0;

double*prt=&arg;

if(*prt==0.0)

return0.0;

for(;*prt;prt++)

result*=*prt;

returnresult;

}

intmain(intargc,char*argv[])

{

setlocale(LC_ALL,"Russian");

cout<<"\n prod(2e0,4e0,3e0,0e0) = "<<prod(2e0,4e0,3e0,0e0);

cout<<"\n prod(1.5,2.0,3.0,0.0) = "<<prod(1.5,2.0,3.0,0.0);

cout<<"\n prod(1.4,3.0,0.0,16.0,84.3,0.0) = "<<

prod(1.4,3.0,0.0,16.0,84.3,0.0);

cout<<"\n prod(0e0) ="<<prod(0e0);

return0;

}

Результат

prod(2e0,4e0,3e0,0e0) = 24

prod(1.5,2.0,3.0,0.0) = 9

prod(1.4,3.0,0.0,16.0,84.3,0.0) = 4.2

prod(0e0) = 0

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

Перегрузка функций в C++ на http://mirrorref.ru


Похожие рефераты, которые будут Вам интерестны.

1. Перегрузка функций. Функции с переменным числом параметров. Передача параметров в функцию по ссылке. Передача параметров по умолчанию

2. Перегрузка бинарных операторов. Перегрузка унарных операторов

3. Исследование функций и построение графиков функций

4. Перегрузка операторов отношений. Операторы преобразования

5. Природа и состав функций менеджмента. Взаимосвязь функций в процессе управления. Специальные функции управления

6. Перегрузка методов. Функциональное назначение. Способ реализации. Примеры применения

7. Перегрузка операций. Функциональное назначение. Способ реализации. Примеры применения

8. Функции, описание, параметры функции. Передача параметров. Перегрузка. Использование шаблонов

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

10. Страхование и его функций