Лекция 9 ПРОИЗВОДНЫЕ ТИПЫ

advertisement
Лекция 9
ПРОИЗВОДНЫЕ
ТИПЫ
Производные типы, зачем ?
! данные N частиц
real x(N)
real y(N)
real z(N)
logical status(N)
real temperature(N)
real pressure(N)
integer color(N)
При сортировке
используются
перестановки элементов.
Перестановка требует 3
операции присваивания.
tmp = x(12)
x(12) = x(15)
x(15) = tmp
Для перестановки двух
частиц потребуется
записать 21(!) операции
присваивания.
Производные типы, зачем ?
Лучше объединить типы под одним "общим типом“.
type particle
real x
real y
real z
logical status
real temperature
real pressure
integer color
end type particle
! координаты
поля
! физические
! параметры
! цвет
type (particle) M(N), tmp
...
tmp = M(12) ! 3 присваивания
M(12) = M(15)
M(15) = tmp
Оператор type
Объявляет новый тип данных,
группируя под одним именем существующие типы.
type имя
типы данных
contains
процедуры привязанные к типу
end type имя
Доступ к полям
Операция " . " или " % ".
program prog
type NewType
integer A
real
B
character C
logical
D
end type NewType
type (NewType) PS
PS.A = 35;
PS%A = 25;
PS.B = 3.14; PS.C = 'E'; PS.D = .FALSE.
PS%B = 5.67; PS%C = 'Q'; PS%D = .TRUE.
end
Задание начальных значений для каждого поля
лучше с использованием конструктора.
Конструктор производного типа
Конструктор – функция с именем производного типа.
Параметры функции - поля производного типа.
program prog
type NewType
integer
A
real
B
character C
logical
D
end type NewType
конструктор
type (NewType) :: PS0 = NewType(1, 0.32, 'Z', .FALSE.)
type (NewType) PS1
type (NewType), allocatable :: PS2
PS1 = NewType(5, 3.5, 'Q', .TRUE.)
allocate(PS2);
PS2 = NewType(8, 1.2, 'F', .TRUE.)
! ИЛИ allocate(PS2, source = NewType(8, 1.2, 'F', .TRUE.))
write(*,*) PS2 ! вывод значений всех полей
end
Иерархия типов
type person
character(128) fio
integer
age
end type person
type firm
type (person) people(1000)
character(128) name
integer
money
end type firm
type (firm) FM
FM.money = 100000 ! доступ к полям
FM.name = 'Siberia'
FM.people(1).fio = 'Ivanov S.K.'
FM.people(1).age = 35
Расширение типа, extends
Тип CHILD наследует поля типа PARENT
type PARENT
! родитель
integer A
real B
end type PARENT
type, extends (PARENT) :: CHILD ! потомок
character C
end type CHILD
type (CHILD) pas1, pas2
pas1 = CHILD(PARENT(1,2.0),'A')
pas2 = CHILD(1,2.0,'A')
Оператор class
Class объявляет полиморфную переменную.
Если полиморфная переменная не является
формальным параметром процедуры, то
используются атрибуты allocatable или pointer.
class (имя производного типа), allocatable :: имя
type PARENT
integer A
real B
end type PARENT
type, extends (PARENT) :: CHILD ! наследуем тип PARENT
character C
end type CHILD
type (CHILD), allocatable :: CL1
class (CHILD), allocatable :: CL2
allocate(CL1, source = CHILD(1,3.0,'Q'))
allocate(CL2, source = CHILD(1,3.0,'Q'))
Переменная CL2 имеет больше возможностей.
Оператор class
Полиморфная переменная объявленная родительским
типом может "принимать" все дочерние типы.
program prog
type PARENT
integer A
real B
end type PARENT
type, extends (PARENT) :: CHILD_A
character C
end type CHILD_A
type, extends (PARENT) :: CHILD_B
logical D
end type CHILD_B
type, extends (CHILD_A) :: CHILD_CHILD_A
complex E
end type CHILD_CHILD_A
Оператор class
class (PARENT), pointer
type
type
type
type
PAR
PAR
PAR
PAR
:: PAR
(PARENT),
target :: P
(CHILD_A), target :: CA
(CHILD_B), target :: CB
(CHILD_CHILD_A), target :: CCA
=>
=>
=>
=>
P
CA
CB
CCA
!
!
!
!
стал родителем
теперь потомок А
изменился на потомка B
теперь потомок потомка А
end
CHILD_A
PARENT
CHILD_B
CHILD_CHILD_A
Конструкция select type
Как определить какой тип имеет
полиморфная переменная ?
Select type позволяет выполнить блок операторов в
зависимости от динамического типа полиморфной
переменной.
select type (переменная)
type is (имя типа)
class is (имя типа)
class default
end select
Оператор select type
Схема выполнения

Находится и выполняется блок type is

Если не найден type is, то находится и
выполняется class is.

Если найдено соответствие нескольким блокам
class is, то выбирается ближайший
родитель.

Если не найден ни один блок выбирается class
default.
Оператор select type
...
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
CHILD_A
PARENT
CHILD_B
CHILD_CHILD_A
Оператор 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 => PT1
PAR => PT2
PAR => CMP
:: PAR
! неограниченно полиморфная
! сейчас типа T1
! теперь типа T2
! затем комплексный тип
Процедурные указатели
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) 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
Атрибут private
(Пример)
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
Атрибут private
(Пример)
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
Приоритет операций
 унарная перегруженная или
задаваемая операция
 арифметические операции
 символьная операция конкатенация
 операции отношения
 логические операции
 задаваемая или перегруженная
бинарная операция
*Задание*
Создать модуль для работы с длинными числами.
Реализовать операции присваивания, сложения и
вывода длинных целых чисел.
Download