Ricerca…


Definizione del tipo derivato

Fortran 2003 ha introdotto il supporto per la programmazione orientata agli oggetti. Questa funzione consente di sfruttare le moderne tecniche di programmazione. I tipi derivati ​​sono definiti con il seguente formato:

TYPE [[, attr-list] :: ] name [(name-list)]
   [def-stmts]
   [PRIVATE statement or SEQUENCE statement]. . .
   [component-definition]. . .
   [procedure-part]
END TYPE [name]

dove,

  • attr-list : una lista di specificatori di attributi
  • nome : il nome del tipo di dati derivato
  • nome-elenco : un elenco di nomi di parametri di tipo separati da virgole
  • def-stmts : una o più dichiarazioni INTEGER dei parametri di tipo nominati nell'elenco dei nomi
  • definizione del componente - una o più istruzioni di dichiarazione del tipo o istruzioni del puntatore di procedura che definiscono il componente del tipo derivato
  • procedura-parte : un'istruzione CONTAINS, eventualmente seguita da un'istruzione PRIVATE e una o più istruzioni di associazione della procedura

Esempio:

type shape
    integer :: color
end type shape

Digitare le procedure

Per ottenere un comportamento simile alla classe, il tipo e le procedure correlate (subroutine e funzioni) devono essere inseriti in un modulo:

Esempio:

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

Più tardi, in un codice, possiamo usare questa classe Shape come segue:

! declare a variable of type Shape
type(Shape) :: shape

! call the type-bound subroutine
call shape%set(10)
call shape%print 

Tipi derivati ​​astratti

Un tipo derivato estensibile può essere astratto

type, abstract :: base_type
end type

Tale tipo derivato non può mai essere istanziato, ad esempio da

type(base_type) t1
allocate(type(base_type) :: t2)

ma un oggetto polimorfico può avere questo come tipo dichiarato

class(base_type), allocatable :: t1

o

function f(t1)
  class(base_type) t1
end function

I tipi astratti possono avere componenti e procedure legate al tipo

type, abstract :: base_type
  integer i
contains
  procedure func
  procedure(func_iface), deferred :: def_func
end type

La procedura def_func è una procedura legata al tipo posticipata con interfaccia func_iface . Tale procedura legata al tipo posticipata deve essere implementata da ciascun tipo di estensione.

Digita estensione

Un tipo derivato è estensibile se non ha né l'attributo bind né l'attributo sequence . Un tal tipo può essere esteso da un altro tipo.

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

Una variabile polimorfica con tipo dichiarato base_type è di tipo compatibile con tipo higher_type e può avere questo come tipo dinamico

class(base_type), allocatable :: obj
allocate(obj, source=higher_type(1,2))

La compatibilità di tipo discende attraverso una catena di bambini, ma un tipo può estendere solo un altro tipo.

Un tipo derivato estendente eredita le procedure legate al tipo dal genitore, ma questo può essere ignorato

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

Tipo costruttore

I costruttori personalizzati possono essere creati per tipi derivati ​​utilizzando un'interfaccia per sovraccaricare il nome del tipo. In questo modo, gli argomenti delle parole chiave che non corrispondono ai componenti possono essere utilizzati durante la costruzione di un oggetto di quel tipo.

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

Questo può essere usato per creare un'API più ordinata rispetto all'utilizzo di routine di inizializzazione separate:

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
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow