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)


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow