Массив подпрограмм абстрактного типа - Fortran - PullRequest
1 голос
/ 14 марта 2019

Снова у меня может возникнуть странный вопрос о том, как я (или мог бы) использовать типы в Фортране.

По сути, я до сих пор представлял собой абстрактный тип AbsBase с хан-интерфейсом. Теперь я могу несколько раз расширять этот тип, определяя дочерние типы , где у меня есть различные определения sub, например,

Рабочий пример


Базовый модуль

module BaseClass

    implicit none

    type, abstract :: AbsBase
    contains
        procedure(subInt), nopass, deferred :: sub
    end type

    interface
        subroutine subInt
            implicit none
        end subroutine subInt
    end interface

end module BaseClass

Child Molude 1

module ChildClass1

    use BaseClass 

    implicit noone

    type, extends(AbsBase) :: Child1
    contains
        procedure, nopass :: sub
    end type

contains

    subroutine sub
        implicit none
        print*, "Do something ..."
    end sub

end module ChildClass1

Child Molude 2

module ChildClass2

    use BaseClass 

    implicit noone

    type, extends(AbsBase) :: Child2
    contains
        procedure, nopass :: sub
    end type

contains

    subroutine sub
        implicit none
        print*, "Do something else ..."
    end sub

end module ChildClass2

Программа

program test

    use ChhildClass1
    use ChhildClass2

    implicit none

    type(Child1) :: c1
    type(Child2) :: c2


    call c1%sub    ! <-- prints "Do something ...      "
    call c2%sub    ! <-- prints "Do somethhing else ..."

end program test

Пока все хорошо, но что, если я захочу определить массив типа вместо двух разных дочерних типов? Я пробовал следующее

нерабочий пример (что я пытаюсь сделать)


Базовый модуль

module BaseClass

    implicit none

    type, abstract :: AbsBase
    contains
        procedure(subInt), nopass, deferred :: sub
    end type

    interface
        subroutine subInt
            implicit none
        end subroutine subInt
    end interface

    type :: BaseWrap
        class(AbsBase), pointer :: p
    end type

end module BaseClass

Программа

program test

    use BaseClass

    implicit none

    type(BaseWrap) :: Child(2) 

    call Child(1)%p%sub   ! <--- This should produce "Do something ..."
    call Child(2)%p%sub   ! <--- This should produce "Do something else ..."

contains

    ! Where to I define the subroutines and how would I do this?

end module ChildClass

На самом деле он компилируется (что было довольно удивительно для меня), но, очевидно, приводит к Ошибка сегментации , поскольку я нигде не определил подпрограммы. Если я правильно понял, я получил с type(BaseWrap) :: Child(2) массив указателей, которые указывают на интерфейс абстрактного типа AbsBase. Как бы я теперь определил две подпрограммы из рабочего примера ? Это вообще возможно?

Спасибо!

Ответы [ 2 ]

2 голосов
/ 15 марта 2019

Что ж, классов, которые вы создали, достаточно, чтобы иметь полиморфное поведение, которое вы, похоже, ищете.Вы можете проверить это следующим образом:

program test
  use :: BaseClass
  implicit none

  type(Child1), target :: c1
  type(Child2), target :: c2
  type(BaseWrap) :: child(2)

  child(1)%p => c1
  child(2)%p => c2

  call child(1)%p%sub    ! <-- prints "Do something ...      "
  call child(2)%p%sub    ! <-- prints "Do somethhing else ..."
end

Но использование элемента allocatable вместо pointer исключит необходимость атрибутов target, помимо прочих преимуществ.

1 голос
/ 15 марта 2019

Ваш дизайн хорош, когда эти подпрограммы так или иначе привязаны к типам, нам их данные и так далее. Вам просто нужно определить указатели, как показал Родриго. Если эти подпрограммы на самом деле не зависят от какого-либо внешнего типа, а дочерние типы на самом деле просто созданы, чтобы содержать разные процедуры, вам не нужна такая сложная конструкция. Вы можете просто хранить указатели процедур в одном типе.

module subs
  implicit none

contains

    subroutine sub1
        print*, "Do something ..."
    end subroutine
    subroutine sub2
        print*, "Do something else ..."
    end subroutine
end module

  use subs

  type sub_wrap
    procedure(sub1), pointer, nopass :: sub
  end type

  type(sub_wrap) :: a(2)

  !one way
  a = [sub_wrap(sub1), sub_wrap(sub2)]

  !another way
!   a(1)%sub => sub1
!   a(2)%sub => sub2

  call a(1)%sub()
  call a(2)%sub()
end
...