next up previous contents
След.: Оператор COMMON и блоки Выше: Модули Пред.: Подмодули   Содержание


Области видимости и связь

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

Область видимости имени -- это участок программы, в котором это имя, будучи определено, сохраняет свой смысл. В частности, объект данных с данным именем в своей области данных доступен по этому имени и имеет определенное значение. Области видимости выделяются: программной единицей (напомним, что это основная программа, процедура, модуль или подмодуль и блок данных § 1), конструкцией BLOCK § 7.4, определением производного типа § 3.6 и телом интерфейса § 11.4 -- за вычетом вложенных областей видимости, во всех случаях. Например, переменные, объявленные в основной программе, доступны во всех местах этой программы, в том числе в определенных в ней внутренних процедурах, которые ограничивают свою, вложенную область видимости. Переменные, определенные в процедуре, недоступны из программы, но определенные в программе -- доступны в процедурах. Этот доступ называется связью по вложенности (см. ниже). Однако внешние процедуры определяют область видимости, которая не вложена в основную программу, поэтому данные взаимно недоступны. Аналогично и с модулями § 12: данные, определенные в модуле, как открытые, так и закрытые, доступны модульным процедурам -- это разновидность связи по вложенности. Использование во вложенной области видимости имен, имеющих смысл в объемлющей области видимости, допускается. Однако при этом объект из объемлющей области видимости перестает быть доступным, поскольку данное имя теперь имеет иной смысл. Так, можно определить внутреннюю функцию SIN в основной программе -- в этом случае вызов функции с этим именем приведет к обращению к этой функции, а встроенная функция, вычисляющая синус, будет недоступна (под этим родовым именем, хотя может быть вызвана другими способами). Это позволяет прозрачно переопределять встроенные функции. Равным образом может быть определена не функция, а переменная с тем же именем, и имя окажется связано с нею, а встроенная функция окажется недоступна. Аналогичная ситуация имеет место при импорте модульных объектов, имена которых совпадают с именами объектов в объемлющей области видимости -- последние окажутся недоступны по имени.

Обратим внимание на следующую тонкость. Если во внутренней либо модульной процедуре объявляется объект данных, то опасности нет -- доступен по указанному имени будет именно этот объект данных, даже если в объемлющей области видимости имеется одноименный объект. Однако если используется неявная типизация, допускающая использование скаляров без объявления, возможны ошибки. Вот пример:

MODULE Rel

...

REAL:: E = M*C**2

CONTAINS

SUBROUTINE A

e = 2.7

...

END SUBROUTINE A

END MODULE Rel

В модуле определена переменная E, имеющая физический смысл (энергии), тогда как в процедуре A -- переменная с тем же (с точностью до регистра символов, который не играет роли в Фортране) именем, но другим смыслом (основание натурального логарифма) -- однако операция присваивания «портит» модульную переменную. Ошибки легко избежать путем декларирования переменной.

Рассмотрим различные виды связи. Под связью понимается доступ к объектам вне текущей области видимости. Различают связь по имени, по наследованию, по указателю и по памяти.

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

Связь по импорту -- это доступ к объектам (процедурам, объектам данных, типам) модуля из иной области видимости посредством оператора USE § 12. Возможно переименование объектов или частичный импорт. Фактически импортированные объекты оказываются в импортирующей области видимости. Так, данные модуля меняются при модификации их в процедуре. Для доступа к модульным данным только для чтения предусмотрен атрибут защищенных данных.

Связь по взаимодействию -- это связь между модульной переменной с атрибутом BIND и переменной языка C, с которая она взаимодействует, или между COMMON-блоком и переменной C. Подробнее взаимодействие с C рассмотрено в § 14.

Связь по конструкции возникает при выполнении конструкций SELECT TYPE § 15.3.2 и ASSOCIATE § 7.5, связывающих селектор с соотвествующим именем.

Связь по вложенности -- это описанный выше доступ к объектам в объемлющей области видимости. Отметим вдобавок, что тело интерфейса имеет связь по вложенности только с теми объектами, с которыми связь установлена посредством оператора IMPORT § 11.4.2. Еще один важный момент: если модульные объекты импортированы в объемлющую область видимости, они доступны со вложенной посредством связи по вложенности, независимо от наличия в ней оператора USE. В частности, даже если во вложенной области видимости осуществляется частичный импорт, все импортированные объекты в объемлющей области видимости объекты доступны посредством связи по вложенности.

Связь по указателю -- это связь между указателем и объектом данных, который является его целью. Указатели детально описаны в § 4.6. Добавим к этому одно замечание: указатель, определенный в модуле, может быть доступен в процедуре посредством связи по импорту. Будучи связан с объектом, определенным в процедуре и не являющимся устойчивым (то есть без атрибута SAVE), он может существовать тогда, когда его цель перестала существовать (по завершении процедуры). Стандарт предписывает считать такие указатели неопределенными, однако не предписывает отслеживать окончание существования целей указателей.

Связь по памяти -- это расположение двух и более объектов данных в одной и той же области памяти или в пересекающихся областях памяти. Возникает вследствие применения оператора EQUIVALENCE и COMMON-блоков (в случае, если блоки с одинаковыми именами определены в разных областях видимости и содержат различные объекты данных). Также к связи по памяти может приводить использование оператора ENTRY. Общие блоки описаны в § 12.3; опишем оператор EQUIVALENCE. Он предназначен специально для организации связи по памяти. После оператора EQUIVALENCE в скобках через запятую перечисляются объекты данных -- скаляры, элементы массивов или подстроки. Таких описаний в скобках может быть более одного -- через запятую. Перечисленные в скобках объекты занимают одну и ту же область памяти. Если они занимают в памяти разный объем, возможны любопытные эффекты.

Связь по наследованию -- это связь между компонентами родительского производного типа и компонентами, унаследованными типом при расширении типа § 15. Например, если компоненты типа инициализируются, то эти компоненты в расширенного типа будут также инициализированы. Более того, компоненты скрытого компонента с именем родительского типа связаны с одноименными компонентами самого расширенного типа. Пример:

TYPE POINT2D

REAL:: X=0.2, Y=0.1

END TYPE POINT

TYPE, EXTENDS(POINT2D):: POINT3D

REAL:: Z = 0.

END TYPE POINT3D

TYPE(POINT3D):: P

PRINT*, T%P%X, T%Y !выводит 0.2 и 0.1

T%X = 9.; t%PY = 8.

PRINT*, T%P%X, T%Y !выводит 9 и 8



Ilya A. Chernov 2012-12-19
X