Fortran
Objekt orientierte Programmierung
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)