Производные типы
Оператор select type
Схема выполнения
- Находится и выполняется блок type is
- Если не найден type is, то находится и выполняется class is.
- Если найдено соответствие нескольким блокам class is, то выбирается ближайший родитель.
- Если не найден ни один блок выбирается class default.
...
type (PARENT), target :: P
type (CHILD_CHILD_A), target :: CCA
PAR => CCA ! потомок потомка А
select type (PAR)
class is (PARENT)
write (*,*) "PARENT"
class is (CHILD_A)
write(*,*) "CHILD" ! выбирается ближайший родитель
class default
write(*,*) "default...."
end select
end
Оператор class(*)
Неограниченно полиморфная переменная принимает любые типы
type T1
integer index
real val
end type T1
type T2
logical status
character symbol
character(10) name
end type T2
complex(16), target :: CMP
type (T1), target :: PT1
type (T2), target :: PT2
class (*), pointer :: PAR ! неограниченно полиморфная
PAR => PT1 ! сейчас типа T1
PAR => PT2 ! теперь типа T2
PAR => CMP ! затем комплексный тип
Процедурные указатели
procedure(proc), pointer :: p1 => null()
Procedure описывает процедурный указатель, позволяет добавлять в созданный тип процедуры.
type NewType
integer a
real b
contains
procedure proc1
procedure :: proc2 => other_pr
end type NewType
...
call A.proc1(a,b)
Атрибуты pass и nopass
Используются для процедур привязанных к производному типу по имени.
pass позволяет получить доступ к переменной, посредством которой вызывалась процедура (по умолчанию).
Вызывающая переменная записывается в процедуре, первым параметром и должна быть объявлена оператором class.
При вызове процедуры данный параметр опускается.
nopass отменяет доступ к вызывающей переменной.
Процедуры привязанные к типу
module algebra
type, public :: vector
real x1, y1, x2, y2
contains
procedure, public, pass :: length
procedure, nopass :: info
end type vector
CONTAINS
subroutine info()
write(*,*) "I'am VECTOR"
end subroutine info
integer function length(vc) ! атрибут pass
class(vector), intent(out) :: vc
length = sqrt((vc.x1-vc.x2)**2 + (vc.y1-vc.y2)**2)
end function length
end module algebra
program prog
use algebra
class (vector), allocatable :: VEC
allocate(VEC, source = vector(0.0,0.0,3.0,4.0))
call VEC.info()
write(*,*) VEC.length() ! формальный параметр отсутствует
! однако при описании объявлен
deallocate(VEC)
end
Завершающие процедуры
Оператор final объявляет процедуры (деструкторы), которые выполняются при удалении ранее размещенных в памяти элементов
type NewType
...
contains
final :: finish
end type NewType
Атрибут private
Используется для задания отдельных полей производных типов в модулях. Доступ к приватной части происходит при помощи public-процедур.
module MyModule
...
type NewType
integer A
real, private :: B
integer C
real, private :: D
end type NewType
...
end module MyModule
Пример
module MyModule
type NewType
integer A
real, private :: B
contains
procedure :: SetParamB
end type NewType
contains
subroutine SetParamB(T,newvalue)
class(NewType) T
real newvalue
if (newvalue < 0) then
write(*,*) "Error in parameter B, must be >=0"
T.B = 0
else
T.B = newvalue
end if
end subroutine
end module
program prog
use MyModule
class(NewType), allocatable :: nw
allocate(nw)
nw.A = 1000
!nw.B = 4.5 ! ошибка доступа
call nw.SetParamB(4.5)
call nw.SetParamB(-9.4) ! некорректные данные
end
Перегрузка операций
Набросок модуля арифметики длинных чисел
module long
type LongNumbe
integer(1) val(length) ! цифры
integer total ! количество
end type LongNumber
contains
subroutine asgn(n,val) ! присваивание
! операторы
end subroutine asgn
function plus(n1,n2) ! операция сложение и другие
! операторы
end function plus
subroutine PrintLong(n) ! вывод числа
! операторы
end subroutine PrintLong
end module long
Набросок вызывающей программы
program prog
use long
type (LongNumber) a, b, c, d
call asgn(a,"2823892839283923837483485555555")
call asgn(b,"92882746")
call asgn(c,"2038493849300000")
!---- хотим найти выражение
! d = a*(b+c)+c*(a+b)+b
d = plus(plus(umn(a,plus(b,c)),umn(c,plus(a,b))),b)
! очень громоздкая запись
! осложнение если будет много операций
call PrintLong(d)
end
Перегрузка операции присваивания
interface assignment (=)
module procedure asgn ! имя процедуры
end interface
Перегрузка операции сложения, умножения и др.
interface operator (+)
module procedure plus ! имя процедуры
end interface
Замена имени процедуры на знак операции.
Унарная операция - функция с одним входным параметром имеющего вид связи IN.
Двуместная операция - функция с двумя параметрами имеющими вид связи IN.
Нельзя изменять тип встроенной операции. (например '*' оформить как унарную).
Процедура, задающая '=' должна быть подпрограммой с двумя параметрами.
- 1-й вид связи OUT или INOUT (левая часть),
- 2-й параметр IN (правая часть).
Задаваемые операции
Вводятся аналогично унарным и двуместным операциям.
Имя операции задаётся по общим правилам.
В выражениях операция ограничивается точками.
interface operator (.PLUS.)
module procedure plus
end interface
...
SUMMA = A.PLUS.B
Приоритет операций
- унарная перегруженная или задаваемая операция
- арифметические операции
- символьная операция конкатенация
- операции отношения
- логические операции
- задаваемая или перегруженная бинарная операция
Задание
Создать модуль для работы с длинными числами. Реализовать операции присваивания, сложения и вывода длинных целых чисел.
