Лекция 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.B = 3.14; PS.C = 'E'; PS.D =.FALSE. PS%A = 25; 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 = ! доступ к полям FM.name = 'Siberia' FM.people(1).fio = 'Ivanov S.K.' FM.people(1).age = 35
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') Расширение типа, extends Тип CHILD наследует поля типа PARENT
Оператор 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 :: PAR type (PARENT), target :: P type (CHILD_A), target :: CA type (CHILD_B), target :: CB type (CHILD_CHILD_A), target :: CCA PAR => P ! стал родителем PAR => CA ! теперь потомок А PAR => CB ! изменился на потомка B PAR => CCA ! теперь потомок потомка А end PARENT CHILD_A 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 PARENT CHILD_A 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 ! неограниченно полиморфная PAR => PT1 ! сейчас типа T1 PAR => PT2 ! теперь типа T2 PAR => CMP ! затем комплексный тип
procedure(proc), pointer :: p1 => null() Процедурные указатели type NewType integer a real b contains procedure proc1 procedure :: proc2 => other_pr end type NewType... call A.proc1(a,b) Procedure описывает процедурный указатель, позволяет добавлять процедуры в созданный тип.
Атрибуты 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
type NewType... contains final :: finish end type NewType Завершающие процедуры Оператор final объявляет процедуры (деструкторы), которые выполняются при удалении ранее размещенных в памяти элементов
module MyModule... type NewType integer A real, private :: B integer C real, private :: D end type NewType... end module MyModule Атрибут private Используется для задания отдельных полей производных типов в модулях. Доступ к приватной части происходит при помощи public - процедур.
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 Атрибут private (Пример)
Перегрузка операций Набросок модуля арифметики длинных чисел. 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," ") call asgn(b," ") call asgn(c," ") !---- хотим найти выражение ! 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
Приоритет операций унарная перегруженная или задаваемая операция арифметические операции символьная операция конкатенация операции отношения логические операции задаваемая или перегруженная бинарная операция
Создать модуль для работы с длинными числами. Реализовать операции присваивания, сложения и вывода длинных целых чисел. * З а д а н и е *