Fortran
Объектно-ориентированное программирование
Поиск…
Определение производного типа
В Fortran 2003 появилась поддержка объектно-ориентированного программирования. Эта функция позволяет использовать современные методы программирования. Производные типы определяются с помощью следующей формы:
TYPE [[, attr-list] :: ] name [(name-list)]
[def-stmts]
[PRIVATE statement or SEQUENCE statement]. . .
[component-definition]. . .
[procedure-part]
END TYPE [name]
где,
- attr-list - список спецификаторов атрибутов
- name - имя производного типа данных
- name-list - список имен параметров типа, разделенных запятыми
- def-stmts - одно или несколько объявлений INTEGER параметров типа, названных в списке имен
- определение компонента - один или несколько операторов объявления типа или операторов указателя процедуры, определяющих компонент производного типа
- procedure-part - оператор CONTAINS, необязательно сопровождаемый оператором PRIVATE, и один или несколько операторов привязки к процедуре
Пример:
type shape
integer :: color
end type shape
Процедуры типа
Чтобы получить поведение класса, тип и связанные с ним процедуры (подпрограмма и функции) должны быть помещены в модуль:
Пример:
module MShape
implicit none
private
type, public :: Shape
private
integer :: radius
contains
procedure :: set => shape_set_radius
procedure :: print => shape_print
end type Shape
contains
subroutine shape_set_radius(this, value)
class(Shape), intent(in out) :: self
integer, intent(in) :: value
self%radius = value
end subroutine shape_set_radius
subroutine shape_print(this)
class(Shape), intent(in) :: self
print *, 'Shape: r = ', self%radius
end subroutine shape_print
end module MShape
Позже, в коде, мы можем использовать этот класс Shape следующим образом:
! declare a variable of type Shape
type(Shape) :: shape
! call the type-bound subroutine
call shape%set(10)
call shape%print
Абстрактные производные типы
Расширяемый производный тип может быть абстрактным
type, abstract :: base_type
end type
Такой производный тип никогда не может быть инстанцирован, например,
type(base_type) t1
allocate(type(base_type) :: t2)
но полиморфный объект может иметь это как объявленный тип
class(base_type), allocatable :: t1
или же
function f(t1)
class(base_type) t1
end function
Абстрактные типы могут содержать компоненты и процедуры с привязкой к типу
type, abstract :: base_type
integer i
contains
procedure func
procedure(func_iface), deferred :: def_func
end type
Процедура def_func
- это процедура отложенного типа с интерфейсом func_iface
. Такая отложенная процедура, связанная с типом, должна выполняться каждым расширяющимся типом.
Расширение типа
Производный тип является расширяемым, если он не имеет ни атрибута bind
ни атрибута sequence
. Такой тип может быть расширен другим типом.
module mod
type base_type
integer i
end type base_type
type, extends(base_type) :: higher_type
integer j
end type higher_type
end module mod
Полиморфная переменная с объявленным типом base_type
совместима с типом типа higher_type
и может иметь это как динамический тип
class(base_type), allocatable :: obj
allocate(obj, source=higher_type(1,2))
Совместимость типов спускается через цепочку детей, но тип может распространяться только на один другой тип.
Расширяющийся производный тип наследует процедуры привязки типа от родителя, но это может быть переопределено
module mod
type base_type
contains
procedure :: sub => sub_base
end type base_type
type, extends(base_type) :: higher_type
contains
procedure :: sub => sub_higher
end type higher_type
contains
subroutine sub_base(this)
class(base_type) this
end subroutine sub_base
subroutine sub_higher(this)
class(higher_type) this
end subroutine sub_higher
end module mod
program prog
use mod
class(base_type), allocatable :: obj
obj = base_type()
call obj%sub
obj = higher_type()
call obj%sub
end program
Тип конструктора
Пользовательские конструкторы могут быть созданы для производных типов, используя интерфейс для перегрузки имени типа. Таким образом, аргументы ключевого слова, которые не соответствуют компонентам, могут использоваться при построении объекта такого типа.
module ball_mod
implicit none
! only export the derived type, and not any of the
! constructors themselves
private
public :: ball
type :: ball_t
real :: mass
end type ball_t
! Writing an interface overloading 'ball_t' allows us to
! overload the type constructor
interface ball_t
procedure :: new_ball
end interface ball_t
contains
type(ball_t) function new_ball(heavy)
logical, intent(in) :: heavy
if (heavy) then
new_ball%mass = 100
else
new_ball%mass = 1
end if
end function new_ball
end module ball_mod
program test
use ball_mod
implicit none
type(ball_t) :: football
type(ball_t) :: boulder
! sets football%mass to 4.5
football = ball_t(4.5)
! calls 'ball_mod::new_ball'
boulder = ball_t(heavy=.true.)
end program test
Это можно использовать для создания более чистого API, чем с использованием отдельных процедур инициализации:
subroutine make_heavy_ball(ball)
type(ball_t), intent(inout) :: ball
ball%mass = 100
end subroutine make_heavy_ball
...
call make_heavy_ball(boulder)