Fortran
Programmation orientée objet
Recherche…
Définition de type dérivée
Fortran 2003 a introduit la prise en charge de la programmation orientée objet. Cette fonctionnalité permet de tirer parti des techniques de programmation modernes. Les types dérivés sont définis sous la forme suivante:
TYPE [[, attr-list] :: ] name [(name-list)]
[def-stmts]
[PRIVATE statement or SEQUENCE statement]. . .
[component-definition]. . .
[procedure-part]
END TYPE [name]
où,
- attr-list - une liste de spécificateurs d'attribut
- name - le nom du type de données dérivé
- name-list - une liste de noms de paramètres de type séparés par des virgules
- def-stmts - une ou plusieurs déclarations INTEGER des paramètres de type nommés dans la liste de noms
- component-definition - une ou plusieurs déclarations de type ou instructions de pointeur de procédure définissant le composant de type dérivé
- procedure-part - une instruction CONTAINS, éventuellement suivie d'une instruction PRIVATE et d'une ou plusieurs instructions de liaison de procédure
Exemple:
type shape
integer :: color
end type shape
Procédures de type
Pour obtenir un comportement de type classe, le type et les procédures associées (sous-routine et fonctions) doivent être placés dans un module:
Exemple:
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
Plus tard, dans un code, nous pouvons utiliser cette classe de forme comme suit:
! declare a variable of type Shape
type(Shape) :: shape
! call the type-bound subroutine
call shape%set(10)
call shape%print
Types dérivés abstraits
Un type dérivé extensible peut être abstrait
type, abstract :: base_type
end type
Un tel type dérivé ne peut jamais être instancié, par exemple en
type(base_type) t1
allocate(type(base_type) :: t2)
mais un objet polymorphe peut avoir ceci comme type déclaré
class(base_type), allocatable :: t1
ou
function f(t1)
class(base_type) t1
end function
Les types abstraits peuvent avoir des composants et des procédures liées aux types
type, abstract :: base_type
integer i
contains
procedure func
procedure(func_iface), deferred :: def_func
end type
La procédure def_func
est une procédure de type différé avec interface func_iface
. Une telle procédure liée à un type différé doit être implémentée par chaque type d'extension.
Extension de type
Un type dérivé est extensible s'il ne possède ni l'attribut bind
ni l'attribut sequence
. Un tel type peut être étendu par un autre type.
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
Une variable polymorphe avec le type déclaré base_type
est de type compatible avec le type higher_type
et peut avoir cela comme type dynamique
class(base_type), allocatable :: obj
allocate(obj, source=higher_type(1,2))
La compatibilité de type descend à travers une chaîne d’enfants, mais un type ne peut étendre qu’un autre type.
Un type dérivé étendu hérite des procédures liées au type du parent, mais cela peut être remplacé
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
Type constructeur
Des constructeurs personnalisés peuvent être créés pour les types dérivés en utilisant une interface pour surcharger le nom du type. De cette façon, les arguments de mots-clés qui ne correspondent pas aux composants peuvent être utilisés lors de la construction d'un objet de ce type.
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
Cela peut être utilisé pour créer une API plus efficace que l'utilisation de routines d'initialisation distinctes:
subroutine make_heavy_ball(ball)
type(ball_t), intent(inout) :: ball
ball%mass = 100
end subroutine make_heavy_ball
...
call make_heavy_ball(boulder)