Fortran
Object georiënteerd programmeren
Zoeken…
Afgeleide typedefinitie
Fortran 2003 introduceerde ondersteuning voor objectgeoriënteerd programmeren. Met deze functie kunt u profiteren van moderne programmeertechnieken. Afgeleide typen worden gedefinieerd met de volgende vorm:
TYPE [[, attr-list] :: ] name [(name-list)]
[def-stmts]
[PRIVATE statement or SEQUENCE statement]. . .
[component-definition]. . .
[procedure-part]
END TYPE [name]
waar,
- attr-list - een lijst met kenmerkspecificaties
- naam - de naam van het afgeleide gegevenstype
- name-list - een lijst met namen van typeparameters gescheiden door komma's
- def-stmts - een of meer INTEGER-verklaringen van de typeparameters die in de naamlijst worden genoemd
- componentdefinitie - een of meer typeaangifte-instructies of procedure-pointerinstructies die de component van het afgeleide type definiëren
- procedure-deel - een CONTAINS verklaring, optioneel gevolgd door een PRIVATE verklaring, en een of meer procedure bindende verklaringen
Voorbeeld:
type shape
integer :: color
end type shape
Type procedures
Om klasse-achtig gedrag te verkrijgen, moeten het type en de bijbehorende procedures (subroutine en functies) in een module worden geplaatst:
Voorbeeld:
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
Later kunnen we in een code deze Shape-klasse als volgt gebruiken:
! declare a variable of type Shape
type(Shape) :: shape
! call the type-bound subroutine
call shape%set(10)
call shape%print
Abstract afgeleide types
Een uitbreidbaar afgeleid type kan abstract zijn
type, abstract :: base_type
end type
Een dergelijk afgeleid type mag nooit worden geïnstantieerd, zoals door
type(base_type) t1
allocate(type(base_type) :: t2)
maar een polymorf object kan dit als het aangegeven type hebben
class(base_type), allocatable :: t1
of
function f(t1)
class(base_type) t1
end function
Abstracte types kunnen componenten en typegebonden procedures hebben
type, abstract :: base_type
integer i
contains
procedure func
procedure(func_iface), deferred :: def_func
end type
De procedure def_func
is een uitgestelde func_iface
procedure met interface func_iface
. Een dergelijke uitgestelde typegebonden procedure moet door elk uitbreidend type worden geïmplementeerd.
Type extensie
Een afgeleid type is uitbreidbaar als het noch het bind
noch het sequence
heeft. Een dergelijk type kan worden uitgebreid met een ander 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
Een polymorfe variabele met het aangegeven type base_type
is type compatibel met type higher_type
en kan dat als dynamisch type hebben
class(base_type), allocatable :: obj
allocate(obj, source=higher_type(1,2))
Type compatibiliteit daalt af door een keten van kinderen, maar een type kan slechts één ander type uitbreiden.
Een uitgebreid afgeleid type neemt type-gebonden procedures over van de ouder, maar dit kan worden opgeheven
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 constructor
Aangepaste constructors kunnen worden gemaakt voor afgeleide typen door een interface te gebruiken om de typenaam te overbelasten. Op deze manier kunnen trefwoordargumenten die niet overeenkomen met componenten worden gebruikt bij het construeren van een object van dat 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
Dit kan worden gebruikt om een nettere API te maken dan met afzonderlijke initialisatieroutines:
subroutine make_heavy_ball(ball)
type(ball_t), intent(inout) :: ball
ball%mass = 100
end subroutine make_heavy_ball
...
call make_heavy_ball(boulder)