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)


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow