Передача данных в функцию по умолчанию

В прототипе функции С++ можно указать значения по умолчанию некоторых формальных параметров. Это позволяет пропустить соответствующие аргументы при вызове функции. На их место компилятор подставит значения, указанные по умолчанию. Параметры по умолчанию должны располагаться последовательно после тех формальных параметров, которые не имеют таких значений. Прототип функция имеет вид:

Тип_результата имя_функции (параметры без значений, параметры со значениями по умолч.);

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

Соответственно, если при вызове функции параметр опускается, то опускаются и все параметры справа.

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

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

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

#include <stdio.h>

void zarplata (char*s, int days=24, float rascenka=3Ø.5);

void main ( )

{

zarplata (“кум”);//работал 24 дня по 3Ø.5 грн/день

zarplata (“брат”, 26); //работал 26 дней по 3Ø.5 грн/день

zarplata (“сват”, 24, 41); //24 дня по 41 грн/день

}

void zarplata (char*s, int days, float rascenka)

{

printf(“%s заработал %f гривен\n”, s, days*rascenka);

}

Ссылки

В С++ есть видоизмененная форма указателя – ссылка. Она может рассматриваться как указатель, который при употреблении всегда разименовывается. Фактически ссылка является еще одним именем или псевдонимом переменной. Объявляется при помощи унарного знака & (амперсанд) и при объявлении сразу же должна быть инициализирована. В общем, это выглядит как

тип &имя_ссылки = имя_переменной;

Например:

float x, &s=x;

Здесь s является ссылкой на переменную х типа float.

Ссылку можно инициализировать только один раз. Здесь уместно сравнить указатель и ссылку. Указатель – это переменная, которая может принимать значения адреса другой переменной определенного типа. Такие адреса можно присваивать несколько раз. Лишь бы это были адреса заданного типа переменных.

Ссылка тоже приобретает адрес, но это адрес конкретной переменной, и поменять его на адрес другой переменной нельзя!

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

По сравнению с использованием указателей удобство в том, что вызывающая функция избавляется от операции взятия адреса (&), а вызываемая – от операций * и à. О ссылках нужно знать следующее:

1. Ссылка не является самостоятельным типом и существует только после инициализации.

2. Какие-либо операции осуществляются не над ссылками, а над объектами, на которые они ссылаются.

3. Ссылка не может ссылаться на другую ссылку или на битовое поле.

4. Не может быть массива ссылок.

5. Не может быть указателей на ссылку, но может быть ссылка на указатель, например int*&rpi;//ссылка на указатель на int.

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

float f(const int &x, float a).

При попытке в процессе выполнения функции f( ) присвоить значение константе х компилятор сообщит об ошибке.

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

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

fukaz( ) – передача результатов с помощью указателей;

fssilka( ) – передача результатов с использованием ссылок.

С целью уменьшения объема программы рассмотрим случай обработки только одного одномерного массива x[1Ø].

#include <stdio.h>

#define Nx 1Ø

void vvod (float x[],int n,char q);

void fukaz(float x[], int n, float*sum_otr,int*kol_Ø, float*sum_pol);

void fssilka(float x[], int n, float &sum_otr, int &kol_Ø, float &sum_pol);

void main( )

{

float x[Nx], s_p, s_o;

int k_nul;

vvod (x, Nx, ‘x’);

fukaz (x,Nx,&s_o,&k_nul,&s_p);

printf(“s_0=%f k_nul=%i s_p=%f\n”,s_o, k_nul, s_p);

//Далее следует вызов функции с передачей данных с помощью ссылок

fssilka(x,Nx,s_o,k_nul,s_p);

printf(“s_o=%f k_nul=%i s_p=%f\n”,s_o,k_nul,s_p);

//Естественно, что результаты совпадают

}

void vvod(float x[],int n,char q)

{

for (int i=Ø; i<n;i++)

{printf(“введите %c[%i]=\n”,q,i);

scanf (“%f”,&x[i]);

}

return;

}

void fukaz(float x[],int n,float*sum_otr,int*kol_Ø,float*sum_pol)

{

*sum_otr=Ø;

*kol_Ø=Ø;

*sum_pol=Ø;

for (int i=Ø; i<n;i++)

if(x[i]< Ø)

*sum_otr+=x[i];

else

if(x[i]> Ø)

*sum_pol+=x[i];

else

*kol_Ø+=1;//(*kol_ Ø)++

}

void fssilka (float x[],int n, float &sum_0 tr,int &kol_Ø,float &sum_pol)

{

sum_otr=kol_Ø=sum_pol=Ø

for (int i= Ø;i<n;i++)

if(x[i]< Ø)

sum_otr+=x[i];

else

if (x[i]> Ø)

sum_pol+=x[i];

else

kol_ Ø++;

}

Перегруженные функции

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

void f(int x) декорированное имя @f$qi. Для void f (char x) - @f$qc.

Для void f(char*x) - @f$qpc.

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

1) если они отличаются только типом возвращаемого результата;

2) если отличаются только применением модификаторов const, volative;

3) если отличие одного типа параметров от другого заключается в наличии в одном из них ссылки.

Ниже следуют примеры пар функций, которые не могут быть перегружены.

void f(int k);

void f(const int k);

void f1(float x);

void f1(float y);

void f2(int x);

void f2(int&a);

Пример перегрузки для функций, используемых для вычисления объемов сферы (V=4/3πR3), параллелепипеда (V=xyz) и цилиндра (V=πR2h).

#include <stdio.h>

#include <math.h>

float v (float R);

float v (float x, float y, float z);

float v(float R, float H);

void main( )

{

float v_sf,v_cil,v_par;

v_sf=v(2.5); //вычисление объема сферы для R=2.5

v_cil=v(3,4.5); // вычисление объема цилиндра для R=3, Н=4.5

v_par=v(2,4, Ø.7); //вычисление объема параллелепипеда

printf(“Объем сферы v_sf=%f\n

Объем цилиндра v_cil=%f\n

Объем параллелепипеда v_par=%f\n”, v_sf,v_cil,v_par);

}

float v(float R)

{

return 4*M_PI*pow(R,3)/3;

}

float v(float R, float H)

{

return M_PI*R*R*H;

}

float v(float x,float y,float z)

{

return x*y*z;

}

Лекция 17

Имена-этикетки

В С++ struct, union, enum являются именами типа переменных точно так, как int, long, float, double и т.д. Поэтому, в отличие от языка С при определении переменных нет необходимости употреблять эти ключевые слова.

Пример 1.

struct man

{

};

man x,y; //Не нужно писать struct man

Пример2.

enum girl {Kate, Ann, Elen};

struct fellow

{

char*name;

girl assistant;

};

fellow x={“Tolik”, Ann};

fellow y,z;

Перед girl не нужно писать enum, а перед fellow – слова struct.

Наши рекомендации