Fortran
Programmazione orientata agli oggetti
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)