Поиск…


Определение производного типа

В 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)


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow