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

long b;  b=8;    

cout << rotate(a) << “\n”;

cout << rotate(b) << “\n”;

return 0;

}

//-------------------------------------------------------------int rotate(int i)    

{

int x;

if ( i & 0x8000) x=1;

else x=0;

i = i<<1;

i += x;

return i;

}

//-------------------------------------------------------------long rotate(long i)    

{

int x;

if ( i & 0x80000000) x=1;

else x=0;

i = i<<1;

i += x;

return i;}

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

Если точного соответствия не найдено, выполняется:

·  продвижение порядковых типов в соответствии с общими правилами (bool  и char в int, float в double и т.д.);

·  стандартные преобразования типов (int  в double, указатели в void*);

·  преобразование типов, заданное пользователем;

·  поиск  соответствий за счет переменного числа аргументов функций.

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

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

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

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

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

·  если описание функций отличается только типом возвращаемого значения (например, int FUN2(int);  и  float FUN2(int);).

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

#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.09f;

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;

          }

Для устранения этой неоднозначности требуется выполнить явное приведение типа для константы 10 (например, static_cast <float> (10) ).

Пример неоднозначности при использовании параметров-ссылок и модификатора const

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

int f(int a, int b); а другая – как            int f(int a, int &b);

и есть вызов функции   f(a, b);

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

Аналогичная ситуация возникает и если описание  параметров отличается только модификатором const.

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

#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) << endl;      //вызывается f(int, int);

//cout << f (10) << endl;       //ошибка компиляции, т.к. имеется неоднозначность                                                           // – что вызывается f(int, int) или f(int) ?

return 0;

}

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

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

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