Выбрать главу

namespace IBM {

int print( int );

}

namespace Disney {

double print( double );

}

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

// формируется множество перегруженных функций из различных

// пространств имен

using namespace IBM;

using namespace Disney;

long double print(long double);

int main() {

print(1); // вызывается IBM::print(int)

print(3.1); // вызывается Disney::print(double)

return 0;

}

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

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

9.1.5. Директива extern "C" и перегруженные функции A

В разделе 7.7 мы видели, что директиву связывания extern "C" можно использовать в программе на C++ для того, чтобы указать, что некоторый объект находится в части, написанной на языке C. Как эта директива влияет на объявления перегруженных функций? Могут ли в одном и том же множестве находиться функции, написанные как на C++, так и на C?

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

// ошибка: для двух перегруженных функций указана директива extern "C"

extern "C" void print( const char* );

extern "C" void print( int );

Приведенный ниже пример перегруженной функции calc() иллюстрирует типичное применение директивы extern "C":

class SmallInt ( /* ... */ );

class BigNum ( /* ... */ );

// написанная на C функция может быть вызвана как из программы,

// написанной на C, так и из программы, написанной на C++.

// функции C++ обрабатывают параметры, являющиеся классами

extern "C" double calc( double );

extern SmallInt calc( const SmallInt );

extern BigNum calc( const BigNum );

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

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

Smallint si = 8;

int main() {

calc( 34 ); // вызывается C-функция calc( double )

calc( si ); // вызывается функция C++ calc( const SmallInt )

// ...

return 0;

}

9.1.6. Указатели на перегруженные функции A

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

extern void ff( vectordouble );

extern void ff( unsigned int );

// на какую функцию указывает pf1?

void ( *pf1 )( unsigned int ) = ff;

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

А что если не найдется функции, в точности соответствующей типу указателя? Тогда компилятор выдаст сообщение об ошибке:

extern void ff( vectordouble );

extern void ff( unsigned int );

// ошибка: соответствие не найдено: неверный список параметров

void ( *pf2 )( int ) = ff;

// ошибка: соответствие не найдено: неверный тип возвращаемого значения

double ( *pf3 )( vectordouble ) = ff;

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

matrix calc( const matrix );

int calc( int, int );

int ( *pc1 )( int, int ) = 0;

int ( *pc2 )( int, double ) = 0;

// ...

// правильно: выбирается функция calc( int, int )

pc1 = calc;

// ошибка: нет соответствия: неверный тип второго параметра

pc2 = calc;