Suche…


Abgeleitete Typdefinition

Fortran 2003 führte die Unterstützung für objektorientierte Programmierung ein. Diese Funktion ermöglicht die Nutzung moderner Programmiertechniken. Abgeleitete Typen werden mit dem folgenden Formular definiert:

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

woher,

  • attr-list - eine Liste von Attributspezifizierern
  • name - der Name des abgeleiteten Datentyps
  • name-list - Eine Liste von Typparameternamen, die durch Kommas getrennt sind
  • def-stmts - Eine oder mehrere INTEGER-Deklarationen der in der Namensliste genannten Typparameter
  • Komponentendefinition - Eine oder mehrere Typdeklarationsanweisungen oder Prozedurzeigeranweisungen, die die Komponente des abgeleiteten Typs definieren
  • procedure-part - Eine CONTAINS-Anweisung, optional gefolgt von einer PRIVATE-Anweisung und einer oder mehreren Prozedurbindungsanweisungen

Beispiel:

type shape
    integer :: color
end type shape

Typ Prozeduren

Um ein klassenähnliches Verhalten zu erhalten, müssen Typ und verwandte Prozeduren (Unterprogramm und Funktionen) in einem Modul angeordnet werden:

Beispiel:

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

Später können wir diese Shape-Klasse in einem Code folgendermaßen verwenden:

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

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

Abstrakte abgeleitete Typen

Ein erweiterbarer abgeleiteter Typ kann abstrakt sein

type, abstract :: base_type
end type

Ein solcher abgeleiteter Typ kann niemals instanziiert werden, wie beispielsweise durch

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

Ein polymorphes Objekt kann dies jedoch als seinen deklarierten Typ haben

class(base_type), allocatable :: t1

oder

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

Abstrakte Typen können Komponenten und typgebundene Prozeduren enthalten

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

Die Prozedur def_func ist eine verzögerte func_iface Prozedur mit der Schnittstelle func_iface . Eine solche verzögerte typgebundene Prozedur muss für jeden Erweiterungstyp implementiert werden.

Typ Erweiterung

Ein abgeleiteter Typ ist erweiterbar, wenn er weder über das bind Attribut noch über das sequence Attribut verfügt. Ein solcher Typ kann um einen anderen Typ erweitert werden.

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

Eine polymorphe Variable mit dem deklarierten Typ " base_type ist mit dem Typ " higher_type kompatibel und kann dies als dynamischen Typ haben

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

Die Typkompatibilität geht durch eine Kette von Kindern ab, aber ein Typ kann nur einen anderen Typ erweitern.

Ein erweiterter abgeleiteter Typ erbt typgebundene Prozeduren vom übergeordneten Element. Dies kann jedoch überschrieben werden

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

Typkonstruktor

Benutzerdefinierte Konstruktoren können für abgeleitete Typen erstellt werden, indem der Typname über eine Schnittstelle überladen wird. Auf diese Weise können Schlüsselwortargumente verwendet werden, die nicht den Komponenten entsprechen, wenn ein Objekt dieses Typs erstellt wird.

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

Dies kann verwendet werden, um eine einfachere API zu erstellen, als mit separaten Initialisierungsroutinen:

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
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow