Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
современный фортран , Бортеньев.pdf
Скачиваний:
272
Добавлен:
26.03.2015
Размер:
2.34 Mб
Скачать
! Задание родового интерфейса
! mymax - родовое имя для функций
! inmax, remax, chmax
! inmax, remax, chmax - специфические
! имена функций, объединенных под ! одним родовым именем mymax

8. Программные единицы

8.12. Перегрузка и родовые интерфейсы

8.12.1. Перегрузка процедур

Иногда полезно иметь возможность обращаться к нескольким процедурам при помощи одного имени. Реализовать подобную возможность можно, объединяя посредством родового интерфейса различные процедуры под одним родовым именем. Имена объединяемых процедур называются специфическими. Сам же механизм вызова разных процедур под одним именем называется перегрузкой. Механизм перегрузки реализован при разработке встроенных процедур (см. разд. 6.3).

Построим, например, функцию mymax(arg1, arg2), возвращающую максимальное значение из двух ее параметров. Параметры функции должны быть одного из следующих типов: INTEGER(4), REAL(4) или CHARACTER(*). Тип результата функции совпадает с типом параметров.

На самом деле для каждого типа параметров придется создать свою функцию, например inmax, remax и chmax, а затем, применив родовой интерфейс, мы объединим созданные функции под одним родовым именем.

program getest interface mymax

function inmax (int1, int2) integer(4) inmax, int1, int2 end function inmax function remax (re1, re2) real(4) remax, re1, re2 end function remax function chmax (ch1, ch2) character(*) ch1, ch2

character(len = max(len(ch1), len(ch2))) chmax end function chmax

end interface

integer(4) :: ia = 1, ib = 2 real(4) :: ra = -1, rb = -2

character(5) :: cha = 'abcde', chb = 'ABCDE'

print *, mymax(ia, ib)

!

2

print *, mymax(ra, rb)

!

-1.000000

print *, mymax(cha, chb)

!

abcde

end program getest

function inmax(int1, int2) integer(4) inmax, int1, int2 if(int1 >= int2) then inmax = int1

else

inmax = int2 end if

end function inmax

247

О. В. Бартеньев. Современный ФОРТРАН

function remax(re1, re2) real(4) remax, re1, re2 if(re1 >= re2) then remax = re1

else

remax = re2 end if

end function remax

function chmax(cha1, cha2) character(*) cha1, cha2

character(len = max(len(cha1), len(cha2))) chmax if(lge(cha1, cha2)) then

chmax = cha1 else

chmax = cha2 end if

end function chmax

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

MODULE PROCEDURE список имен процедур

в котором перечисляются имена всех модульных процедур для перегрузки. Например:

module gemod interface mymax

module procedure inmax, remax, chmax end interface

contains

function inmax(int1, int2)

...

end function inmax function remax(re1, re2)

...

end function remax function chmax(cha1, cha2)

...

end function chmax end module gemod

program getest

 

use gemod

 

print *, chmax('abcde', 'ABCDE')

! Вызов процедуры можно выполнить,

end program getest

! используя ее специфическое имя

248

8. Программные единицы

Замечание. Фортран 95 позволяет завершать интерфейсный блок родовым именем. Например:

interface mymax

! Задание родового интерфейса

module procedure inmax, remax, chmax

end interface mymax

! Завершаем блок родовым именем mymax

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

program getest

! Модуль fuma содержит функции inmax, remax,

use fuma

interface mymax

! chmax, но не содержит родового интерфейса

module procedure inmax, remax, chmax

end interface

 

print *, chmax('abcde', 'ABCDE')

! abcde

end program getest

 

Объединяемые процедуры могут иметь разное число параметров. Также под одним именем могут быть перегружены и подпрограммы и функции.

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

Родовое имя может также совпадать с другим доступным, например через use-ассоциирование, родовым именем. Тогда с помощью этого имени могут быть вызваны все охватываемые им процедуры.

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

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

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

Пример нарушения второго условия:

interface fu12

! Каждый из формальных параметров f1 имеет

function f1(x, i)

real f1, x

! аналог среди формальных параметров функции f2

integer i

! И наоборот, каждый из формальных параметров f2

end function f1

! имеет аналог среди формальных параметров f1

function f2(i, x)

 

real f2, x

 

integer i

 

249

О. В. Бартеньев. Современный ФОРТРАН

end function f2 end interface

Компилятор CVF, получивший такие интерфейсы, выдаст сообщение: Error: The type/rank/keyword signature for this specific procedure matches another specific procedure that shares the same generic-name. [F2] function f2(i, x).

8.12.2. Перегрузка операций и присваивания

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

INTERFACE OPERATOR(задаваемая операция)

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

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

module tdes

! Демонстрация перегрузки операции сложения

type ire

 

integer a

! Перегрузка операций для производных типов

real ra

! необходима, поскольку для них не существует

end type ire

! ни одной встроенной операции

end module tdes

 

module plup

 

use tdes

! Задание операции сложения для типа ire

interface operator(+)

module procedure funir

 

end interface

 

contains

 

function funir(rec1, rec2)

! Параметры задающей операцию функции

type(ire) funir

! должны иметь вид связи IN

type(ire), intent(in) :: rec1, rec2

funir = ire(rec1.a + rec2.a, rec1.ra + rec2.ra) end function funir

end module plup

250

 

 

 

 

8. Программные единицы

program top

! Тип ire передается через модули plup - tdes

use plup

integer :: ia = 1, ib = -1, ic

 

 

 

 

type(ire) :: t1 = ire(1, 1.0), t2 = ire(2, 2.0), t3 = ire(3, 3.0), t4

ic = ia + ib

! Выполняется встроенная операция сложения

t4 = t1 + t2 + t3

! Выполняется заданная операция сложения

print *, ic, t4

!

0

6

6.000000

end

 

 

 

 

При перегрузке встроенной операции нельзя изменять число ее операндов. Так, нельзя задать унарную операцию умножения. Поскольку операции отношения имеют две формы, например (.LE. и <=), то заданный для них интерфейс распространяется на каждую из форм.

Таким же образом можно ввести и новую операцию. Имя вводимой операции должно обрамляться точками. Например, для обозначения операции сложения переменных типа ire можно было бы ввести операцию

.plus.:

interface operator(.plus.)

Тогда применение вновь введенной операции может быть таким: t3 = t1 .plus. t2 .plus. t3

Как и встроенная, вновь вводимая операция может быть распространена на разные типы операндов.

Также можно выполнить перегрузку присваивания. Интерфейсный блок при перегрузке присваивания имеет заголовок

INTERFACE ASSIGNMENT(=)

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

Пример. Задать присваивание для выполнения инициализации производного типа данных.

module tic type icha integer a, b

character(10) fi, se end type icha

end module tic

module oves use tic

251