Значения параметров по умолчанию.




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

int f(int a, int b = 0);

void f1(int, int = 100, char* = 0); /*обратите внимание на пробел между * и = без него получилась бы операция сложного присваивания */

void err(int errValue = errno) //errno- глобальная переменная

.......

f(100); f(a, 1); //так можно

f1(a); f1(a, 10); f1(a, 10, ‘Vasia’); //и так тоже можно

f1(a,,’Vasia’); //а так нельзя!

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

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

Компилятор определяет, какую именно функцию требуется вызвать, по типу фактических параметров. Этот процесс называется разрешением перегрузки, от resolution в смысле «уточнение». Тип возвращаемого функцией значения в разрешении не участвует. Механизм разрешения основан на достаточно сложном наборе правил, смысл которых сводиться к тому, что бы использовать функцию с наиболее подходящими аргументами и выдать сообщение, если такая не найдется. Допустим, имеется 4 варианта функции, определяющей наибольшее значение:

int max(int, int);

char* max(char*, char*);//максимум из длин строк

int max(int, char*);//максимум из целого и длины строки

int max(char*, int);

void f(int a, int b, char* c, char* d){

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

}

Здесь последовательно вызовутся все 4 варианта функции.

Если точного соответствия не найдено, выполняются передвижения порядковых типов в соответствии с общими правилами: bool и char в int, float в double и т.д. Далее выполняются стандартные преобразования типов, int в double, или указателей в void*. следующим шагом являются преобразования типов, заданных пользователем, а так же поиск соответствия за счет переменного числа аргументов функции. Если соответствие на одном и том же этапе может быть получено более чем одним способом, вызов считается неоднозначным и выдается сообщение об ошибке.

Неоднозначность может появиться при:

· преобразовании типа

· использовании параметров- ссылок

· использовании аргументов по умолчанию

Пример неоднозначности преобразования типов:

#include <iostream.h>

float f(float i){

cout << "function float f(float i)" << endl;

return i;

}

double f(double i){

cout << "function double f(double i)" << endl;

return i*2;

}

int main(){

float x = 10.09;

double y = 10.09;

cout << f(x) << endl;

cout << f(y) << endl;

/*cout << f(10) << endl;*/

return 0;

}

Для устранения данной неоднозначности требуется явное преобразование типа для константы 10: cout << f(double (10)) << endl;

Пример неоднозначности при использовании параметров-ссылок: если одна из перегружаемых функций объявлена как int f(int a, int b), а другая как int f(int a, int& b), т.к. нет синтаксических различий между вызовом функции, которая получает параметр по значению, и вызовом функции, которая получает параметр по ссылке.

Пример неоднозначности при использовании аргументов по умолчанию:

#include <iostream.h>

int f(int a){return a;}

int f(int a, int b = 1){return a*b;}

int main(){

cout << f(10, 2);

/* cout << f(10) не понятно какая из функций вызывается*/

return 0;

}

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

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

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

· Функции не могут быть перегружены, если их описание параметров отличаются только модификаторами const или использованием ссылки (например, int и const int, int и &int).

 

Указатели

void f(int x){ x = 7;}main(){ int y = 17; f(y); printf("y=%d\n", y); /* печатает: y=17 */}

В аргументе x передаётся копия значения y, поэтому x=7; не изменяет значения у. Для того, чтобы вызываемая функция могла изменять значение переменной используются указатели.

void f(int *ptr){ *ptr = 7; }main (){ int y=17; f(&y); printf("y=%d\n", y); /* печатает: y=7 */}

Здесь &y обозначает "указатель на переменную y" или "адрес переменной y", *ptr означает "разыменование указателя ptr", int *ptr; означает объявление переменной ptr, которая может содержать в себе указатель на переменную, хранящую int-число.

Указатели несколько различно ведут себя слева и справа от оператора присваивания.

Справа от присваиваний и в формулах *pointer означает "взять значение переменной, на которую указывает указатель, хранящийся в переменной pointer".

Слева от присваивания *pointer = 123; означает "положить значение правой части (т.е. 123) в переменную, на которую указывает указатель, хранящийся в переменной pointer".

Пример: обмен значений двух переменных с использованием адресов и указателей.void swap(int *a, int *b){ int tmp; tmp = *a; *a = *b; *b = tmp;}void main(){ int x, y; x = 1; y = 2; swap(&x, &y); printf("x=%d y=%d\n", x, y);}

 



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2022-11-01 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: