Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции по С++ глава 2.doc
Скачиваний:
6
Добавлен:
05.11.2018
Размер:
249.86 Кб
Скачать

2.3.3. Операция расширения области видимости

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

double A;

void main()

{

int A;

A = 5; // присваивает значение 5 переменной А типа int

}

Однако в языке C++ можно организовать доступ к глобальной переменной (т.е., переменной, объявленной снаружи любой функции), даже если она скрыта локальной с аналогичным именем. Для этого перед именем переменной указывается оператор расширения области видимости ::, например:

double A; // глобальная переменная А

void main()

{

int A; // локальная переменная А

А = 5; // присваивает значение 5 локальной переменной А типа int

::А = 2.5; // присваивает значение 2,5 глобальной переменной А типа double

}

Обратите внимание: операция расширения области видимости используется только для организации доступа к глобальной переменной. Данную операцию нельзя использовать для доступа к локальной переменной, объявленной внутри блока, как в следующем примере некорректного кода:

void FuncX(int Code)

{

double A;

if (Code == 1)

{

int A;

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

::А = 2.5; // СШИБКА: ::А описывает глобальную переменную А, что неправильно,

// если А не определена на глобальном уровне

// ...

}

// ...

}

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

#include <iostreara.h>

typedef int A;

enum (Red, White, Blue);

void main ()

{

typedef double A;

enum (Blue, White, Red);

cout << sizeof (A) << '\n'; // печатает размер переменной // А типа double

cout << sizeof (::A) << '\n'; // печатает размер переменной // А типа int

cout << (int)Blue << ‘\n'; // печатает О

cout << (int)::Blue << '\n'; // печатает 2

}

2.3.4. Встроенные функции

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

inline int FuncA(int X)

{

// код функции ...

}

Замена вызовов функции копией кода функции называется макрорасширением (inline expansion) или просто встраиванием (inlining).

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

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

Механизм встраивания напоминает работу макросов, определенных с использованием директивы препроцессора #define. Например, следующая функция, предназначенная для возвращения абсолютной величины целого числа

inline int Abs(int N) {return N < 0 ? -N : N;}

подобна макросу

#define ABS(N) ((N) < 0 ? -(N) : (N));

Но есть и отличие: вызовы встроенной функции обрабатываются компилятором, а макросов – препроцессором, выполняющим простую текстовую подстановку. Следовательно, встроенная функция имеет два важных преимущества перед макросом. Во-первых, при вызове функции компилятор проверяет тип передаваемых ей параметров, чтобы убедиться в том, что они целочисленные или их значения можно преобразовать в целочисленные. Во-вторых, если функции передается выражение, го оно вычисляется всего один раз. Если же выражение передается в макрос, то оно вычисляется дважды, что может привести к неожиданным результатам. Например, следующий вызов макроса дважды декрементирует переменную I (возможен неожиданный или нежелательный результат!):

Abs (--I);

Макрос также имеет преимущество перед встроенной функцией: ему можно передать данные любого типа и он возвратит результат такого же типа (например, long, int или double). Хотя во встроенную функцию также можно передать аргумент любого числового типа, тип значения будет преобразован в int, а функция возвратит значение типа int, в результате чего может быть потеряна точность. Однако, как будет показано далее (в разделе «Перегруженные функции»), в языке C++ эти ограничения преодолеваются путем определения нескольких вариантов функции, по одному для каждого типа или для множества типов параметров, передаваемых функции.

Примечание

Описание встроенных функций, являющихся членами классов, приведено в следующей главе.