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

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

moveAbs(int,

int);

несколько функций в одну. Например, функции управления курсором moveAbs(int, int, char*);

различаются наличием третьего параметра типа char*. Если их реализации похожи и для третьего аргумента можно найти разумное значение по умолчанию, то обе функции можно заменить одной. В данном случае на роль значения по умолчанию подойдет указатель со значением 0:

move( int, int, char* = 0 );

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

9.1.4. Перегрузка и область видимости A

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

#include <string>

void print( const string & );

void print( double );

// перегружает print()

void fooBar( int ival )

{

// отдельная область видимости: скрывает обе реализации print()

extern void print( int );

// ошибка: print( const string & ) не видна в этой области print( "Value: ");

print( ival );

// правильно: print( int ) видна

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

}

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

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

#include <string> namespace IBM {

extern

void

print(

const string &

);

extern

void

print(

double ); //

перегружает print()

}

namespace Disney {

//отдельная область видимости:

//не перегружает функцию print() из пространства имен

IBM

extern void print( int );

}

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

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

namespace libs_R_us { int max( int, int );

int max( double, double );

extern void print( int ); extern void print( double );

}

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

using libs_R_us::print( double ); // ошибка

void func()

 

{

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

max( 87, 65 );

int )

 

это объявление встречается. Что делают такие объявления в следующей программе? max( 35.5, 76.6 ); // вызывает libs_R_us::max( double, double )

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

using libs_R_us::print;

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

print( 88 );

автор пространства имен ожидает, что будет вызвана функция libs_R_us::print(int). Если разрешить пользователю избирательно включать в область видимости лишь одну из

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

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

#include <string> namespace libs_R_us {

extern void print( int ); extern void print( double );

}

extern void print( const string & );

//libs_R_us::print( int ) и libs_R_us::print( double )

//перегружают print( const string & )

using libs_R_us::print;

void fooBar( int ival )

{

print( "Value: ");

// вызывает глобальную функцию

print( ival );

// print( const string & )

// вызывает

libs_R_us::print( int )

области видимости:

}

Using-объявление добавляет в глобальную область видимости два объявления: для print(int) и для print(double). Они являются псевдонимами в пространстве libs_R_us и включаются в множество перегруженных функций с именем print, где уже находится глобальная print(const string &). При разрешении перегрузки print в fooBar рассматриваются все три функции.

Если using-объявление вводит некоторую функцию в область видимости, в которой уже имеется функция с таким же именем и таким же списком параметров, это считается ошибкой. С помощью using-объявления нельзя задать псевдоним для функции print(int) в пространстве имен libs_R_us, если в глобальной области видимости уже

namespace libs_R_us { void print( int ); void print( double );

}

void print( int );

using libs_R_us::print; // ошибка: повторное объявление print(int)

void fooBar( int ival )

{

print( ival ); // какая print? ::print или libs_R_us::print

есть print(int). Например:

}

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

#include <string> namespace libs_R_us {

extern void print( int ); extern void print( double );

}

extern void print( const string & );

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

//print(int), print(double) и print(const string &) -

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

using namespace libs_R_us;

void fooBar( int ival )

{

print( "Value: ");

// вызывает глобальную функцию

print( ival );

// print( const string & )

// вызывает libs_R_us::print( int )

именем, то происходит перегрузка. Например:

}

Это верно и в том случае, когда есть несколько using-директив. Одноименные функции,

namespace IBM { int print( int );

}

namespace Disney { double

print( double );

являющиеся членами разных пространств, включаются в одно и то множество:

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

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

различных // пространств имен using namespace IBM;

using namespace Disney;

long double print(long double);

int main() {

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

print(1);

print(3.1);

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

return 0;

 

}

 

}

 

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