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

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

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

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

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

SmallInt

si(1

5);

Предположим, что имеется такой вызов: add( si, 566 );

Функция-кандидат должна иметь имя add. Какие из объявлений add() принимаются во внимание? Те, которые видимы в точке вызова.

Например, обе функции add(), объявленные в глобальной области видимости, будут

const matrix& add( const matrix &, int );

double add( double, double );

int main() { SmallInt si(15); add( si, 566 ); // ...

кандидатами для следующего вызова:

}

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

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

namespace NS {

class SmallInt { /* ... */ }; class String { /* ... */ };

String add( const String &, const String & );

}

int main() {

//si имеет тип class SmallInt:

//класс объявлен в пространстве имен NS NS::SmallInt si(15);

add( si, 566 ); // NS::add() - функциякандидат

return 0;

}

Аргумент si имеет тип SmallInt, т.е. тип класса, объявленного в пространстве имен NS. Поэтому к множеству функций-кандидатов добавляется add(const String &, const String &), объявленная в этом пространстве имен;

если фактический аргумент – это объект типа класса, указатель или ссылка на класс либо указатель на член класса и у этого класса есть друзья, имеющие то же имя, что и

namespace NS { class SmallInt {

friend SmallInt add( SmallInt, int ) { /* ...

*/ }

};

}

int main() { NS::SmallInt si(15);

add( si, 566 ); // функция-друг add() - кандидат return 0;

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

}

Аргумент функции si имеет тип SmallInt. Функция-друг класса SmallInt add(SmallInt, int) – член пространства имен NS, хотя непосредственно в этом пространстве она не объявлена. При обычном поиске в NS функция-друг не будет найдена. Однако при вызове add() с аргументом типа класса SmallInt принимаются во внимание и добавляются к множеству кандидатов также друзья этого класса, объявленные в списке его членов.

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

Рассмотрим следующий пример:

namespace NS { class SmallInt {

friend SmallInt add( SmallInt, int ) { /* ...

*/ }

};

class String { /* ... */ };

String add( const String &, const String & );

}

const matrix& add( const matrix &, int ); double add( double, double );

int main() {

//si имеет тип class SmallInt:

//класс объявлен в пространстве имен NS NS::SmallInt si(15);

add( si, 566 ); // вызывается функция-друг return 0;

}

Здесь кандидатами являются:

const matrix& add( const matrix &, int )

глобальные функции: double add( double, double )

функция из пространства имен:

NS::add( const String &, const String & )

функция-друг:

NS::add( SmallInt, int )

При разрешении

перегрузки выбирается функция-друг класса SmallInt

NS::add( SmallInt,

int ) как наилучшая из устоявших: оба фактических аргумента

точно соответствуют заданным формальным параметрам.

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

15.10.3. Функции-кандидаты для вызова функции в области видимости класса

Когда вызов функции вида

calc(t)

встречается в области видимости класса (например, внутри функции-члена), то первая часть множества кандидатов, описанного в предыдущем подразделе (т.е. множество, включающее объявления функций, видимых в точке вызова), может содержать не только функции-члены класса. Для построения такого множества применяется разрешение имени. (Эта тема детально разбиралась в разделах 13.9 – 13.12.)

namespace NS {

struct myClass {

void k( int );

static void k( char* );

void mf();

};

 

int k( double );

};

 

void h(char);

void NS::myClass::mf() {

h('a');

// вызывается глобальная

k(4);

h( char )

// вызывается myClass::k( int )

Рассмотрим пример:

}

Как отмечалось в разделе 13.11, квалификаторы NS::myClass:: просматриваются в обратном порядке: сначала поиск видимого объявления для имени, использованного в определении функции-члена mf(), ведется в классе myClass, а затем – в пространстве имен NS. Рассмотрим первый вызов:

h( 'a' );

При разрешении имени h() в определении функции-члена mf() сначала просматриваются функции-члены myClass. Поскольку функции-члена с таким именем в области видимости этого класса нет, то далее поиск идет в пространстве имен NS. Функции h()нет и там, поэтому мы переходим в глобальную область видимости. Результат – глобальная функция h(char), единственная функция-кандидат, видимая в точке вызова.

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

k( 4 );

Сначала поиск ведется в области видимости класса myClass. При этом найдены две функции-члена k(int) и k(char*). Поскольку множество кандидатов содержит лишь функции, объявленные в той области, где разрешение успешно завершилось, то пространство имен NS не просматривается и функция k(double) в данное множество не включается.