Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Еще раз о разрешении перегрузки функций



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

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

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

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

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

SmallInt si(15);

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 ) как наилучшая из устоявших: оба фактических аргумента точно соответствуют заданным формальным параметрам.

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


Поделиться:



Последнее изменение этой страницы: 2019-04-09; Просмотров: 286; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.018 с.)
Главная | Случайная страница | Обратная связь