Fortran
Programación orientada a objetos
Buscar..
Definición de tipo derivado
Fortran 2003 introdujo el soporte para la programación orientada a objetos. Esta característica permite aprovechar las modernas técnicas de programación. Los tipos derivados se definen con la siguiente forma:
TYPE [[, attr-list] :: ] name [(name-list)]
[def-stmts]
[PRIVATE statement or SEQUENCE statement]. . .
[component-definition]. . .
[procedure-part]
END TYPE [name]
dónde,
- attr-list - una lista de especificadores de atributos
- nombre - el nombre del tipo de datos derivado
- nombre-lista - una lista de nombres de parámetros de tipo separados por comas
- def-stmts : una o más declaraciones INTEGER de los parámetros de tipo nombrados en la lista de nombres
- definición de componente : una o más declaraciones de declaración de tipo o instrucciones de puntero de procedimiento que definen el componente de tipo derivado
- procedure-part : una declaración CONTAINS, opcionalmente seguida de una declaración PRIVATE y una o más instrucciones vinculantes de procedimiento
Ejemplo:
type shape
integer :: color
end type shape
Tipo de Procedimientos
Para obtener un comportamiento similar a una clase, el tipo y los procedimientos relacionados (subrutina y funciones) se colocarán en un módulo:
Ejemplo:
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
Más adelante, en un código, podemos usar esta clase de Forma de la siguiente manera:
! declare a variable of type Shape
type(Shape) :: shape
! call the type-bound subroutine
call shape%set(10)
call shape%print
Tipos derivados abstractos
Un tipo derivado extensible puede ser abstracto
type, abstract :: base_type
end type
Tal tipo derivado nunca puede ser instanciado, tal como por
type(base_type) t1
allocate(type(base_type) :: t2)
pero un objeto polimórfico puede tener esto como su tipo declarado
class(base_type), allocatable :: t1
o
function f(t1)
class(base_type) t1
end function
Los tipos abstractos pueden tener componentes y procedimientos de tipo unido
type, abstract :: base_type
integer i
contains
procedure func
procedure(func_iface), deferred :: def_func
end type
El procedimiento def_func
es un procedimiento de tipo diferido con interfaz func_iface
. Este tipo de procedimiento diferido debe ser implementado por cada tipo de extensión.
Extensión de tipo
Un tipo derivado es extensible si no tiene el atributo de bind
ni el atributo de sequence
. Tal tipo puede ser extendido por otro tipo.
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
Una variable polimórfica con el tipo base_type
declarado es compatible con el tipo higher_type
y puede tenerlo como tipo dinámico
class(base_type), allocatable :: obj
allocate(obj, source=higher_type(1,2))
La compatibilidad de tipos desciende a través de una cadena de hijos, pero un tipo puede extenderse solo a otro tipo.
Un tipo derivado extendido hereda los procedimientos de tipo enlazado del padre, pero esto puede ser anulado
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
Tipo constructor
Se pueden crear constructores personalizados para tipos derivados utilizando una interfaz para sobrecargar el nombre del tipo. De esta manera, los argumentos de palabras clave que no corresponden a componentes pueden usarse al construir un objeto de ese tipo.
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
Esto se puede usar para hacer una API más ordenada que usar rutinas de inicialización separadas:
subroutine make_heavy_ball(ball)
type(ball_t), intent(inout) :: ball
ball%mass = 100
end subroutine make_heavy_ball
...
call make_heavy_ball(boulder)