Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ для начинающих.pdf
Скачиваний:
183
Добавлен:
01.05.2014
Размер:
3.97 Mб
Скачать

(a)void print( int *, int ); int arr[6];

print( arr, 6 ); // вызов функции

(b)void manip( int, int );

manip( 'a', 'z' ); // вызов функции

(c)int calc( int, int );

double dobj;

double = calc( 55.4, dobj ) // вызов функции

(d)void set( const int * ); int *pi;

set( pi ); // вызов функции

Упражнение 9.8 Какие из данных вызовов ошибочны из-за того, что не существует преобразования между

(a)enum Stat { Fail, Pass }; void test( Stat );

text( 0 ); // вызов функции

(b)void reset( void *);

reset( 0 ); // вызов функции

(c)void set( void * ); int *pi;

set( pi ); // вызов функции

(d)#include <list> list<int> oper();

void print( oper() ); // вызов функции

(e)void print( const int ); int iobj;

типом фактического аргумента и формального параметра: print( iobj ); // вызов функции

9.4. Детали разрешения перегрузки функций

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

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

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

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

Теперь мы готовы к тому, чтобы изучить эти шаги более детально.

9.4.1. Функции-кандидаты

Функцией-кандидатом называется функция, имеющая то же имя, что и вызванная. Кандидаты отыскиваются двумя способами:

void f(); void f( int );

void f( double, double = 3.4 ); void f( char*, char* );

int main() {

f( 5.6 ); // для разрешения этого вызова есть четыре кандидата

return 0;

∙ объявление функции видимо в точке вызова. В следующем примере

}

все четыре функции f() удовлетворяют этому условию. Поэтому множество кандидатов содержит четыре элемента;

если тип фактического аргумента объявлен внутри некоторого пространства имен, то функции-члены этого пространства, имеющие то же имя, что и

namespace NS {

class C { /* ... */ }; void takeC( C& );

}

// тип cobj - это класс C, объявленный в пространстве имен NS NS::C obj;

int main() {

// в точке вызова не видна ни одна из функций takeC() takeC( cobj); // правильно: вызывается NS::takeC( C& ),

//потому что аргумент имеет тип NS::C, следовательно,

//принимается во внимание функция takeC(),

//объявленная в пространстве имен NS

return 0;

вызванная функция, добавляются в множество кандидатов:

}

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

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

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

следующем примере функциями-кандидатами, видимыми в точке вызова, являются

char* format( int ); void g() {

char *format( double ); char* format( char* );

format(3); // вызывается format( double )

format(double) и format(char*):

}

Так как format(int), объявленная в глобальной области видимости, скрыта, она не включается в множество функций-кандидатов.

namespace libs_R_us { int max( int, int );

double max( double, double );

}

char max( char, char );

void func()

{

//функции из пространства имен невидимы

//все три вызова разрешаются в пользу глобальной функции

max( char, char ) max( 87, 65 );

max( 35.5, 76.6 ); max( 'J', 'L' );

Кандидаты могут быть введены с помощью using-объявлений, видимых в точке вызова:

}

Функции max(), определенные в пространстве имен libs_R_us, невидимы в точке вызова. Единственной видимой является функция max() из глобальной области; только она входит в множество функций-кандидатов и вызывается при каждом из трех обращений к func(). Мы можем воспользоваться using-объявлением, чтобы сделать видимыми функции max() из пространства имен libs_R_us. Куда поместить using-

char max( char, char );

объявление? Если включить его в глобальную область видимости: using libs_R_us::max; // using-объявление

то функции max() из libs_R_us добавляются в множество перегруженных функций, которое уже содержит max(), объявленную в глобальной области. Теперь все три функции видны внутри func() и становятся кандидатами. В этой ситуации вызовы func() разрешаются следующим образом:

void func()

 

{

// вызывается libs_R_us::max( int, int )

max( 87, 65 );

max( 35.5, 76.6 ); // вызывается libs_R_us::max( double,

double )

// вызывается ::max( char, char )

max( 'J', 'L' );

}

Но что будет, если мы введем using-объявление в локальную область видимости функции

void func()

{

//using-объявление using libs_R_us::max;

//те же вызовы функций, что и выше

func(), как показано в данном примере?

}

Какие из функций max() будут включены в множество кандидатов? Напомним, что using-объявления вкладываются друг в друга. При наличии такого объявления в локальной области глобальная функция max(char, char) оказывается скрытой, так что

libs_R_us::max( int, int );

в точке вызова видны только libs_R_us::max( double, double );

void func()

{

//using-объявление

//глобальная функция max( char, char ) скрыта using libs_R_us::max;

max( 87, 65 );

// вызывается libs_R_us::max( int, int )

max( 35.5, 76.6 ); // вызывается libs_R_us::max( double,

double )

// вызывается libs_R_us::max( int, int )

max( 'J', 'L' );

Они и являются кандидатами. Теперь вызовы func() разрешаются следующим образом:

}

Using-директивы также оказывают влияние на состав множества функций-кандидатов. Предположим, мы решили их использовать, чтобы сделать функции max() из пространства имен libs_R_us видимыми в func(). Если разместить следующую usingдирективу в глобальной области видимости, то множество функций-кандидатов будет состоять из глобальной функции max(char, char) и функций max(int, int) и max(double, double), объявленных в libs_R_us:

namespace libs_R_us { int max( int, int );

double max( double, double );

}

char max( char, char );

using namespace libs_R_us; // using-директива

void func()

 

{

// вызывается libs_R_us::max( int, int )

max( 87, 65 );

max( 35.5, 76.6 ); // вызывается libs_R_us::max( double,

double )

// вызывается ::max( int, int )

max( 'J', 'L' );

}

Что будет, если поместить using-директиву в локальную область видимости, как в

void func()

{

// using-директива

using namespace libs_R_us;

// те же вызовы функций, что и выше

следующем примере?

}

Какие из функций max() окажутся среди кандидатов? Напомним, что using-директива делает члены пространства имен видимыми, словно они были объявлены вне этого пространства, в той точке, где такая директива помещается. В нашем примере члены libs_R_us видимы в локальной области функции func(), как будто они объявлены вне пространства – в глобальной области. Отсюда следует, что множество перегруженных

max( char, char ); libs_R_us::max( int,

int );

функций, видимых внутри func(), то же, что и раньше, т.е. включает в себя libs_R_us::max( double, double );

В локальной или глобальной области видимости появляется using-директива, на

void func()

{

using namespace libs_R_us;

max( 87, 65 );

//

вызывается

libs_R_us::max(

int, int )

max( 35.5, 76.6 ); // вызывается libs_R_us::max( double,

double )

// вызывается ::max( int, int )

max( 'J', 'L' );

разрешение вызовов функции func() не влияет:

}