Как использовать типы в подмодулях Fortran - PullRequest
0 голосов
/ 06 марта 2019

У меня есть базовый модуль , который определяет некоторые подпрограммы (sub1, sub2, sub3). Затем я хочу переопределить эти подпрограммы в серии дочерних модулей .

Я знаю, как это сделать с отдельными модулями и отложенными типами, но я решил попробовать его с подмодулями . К сожалению, я не понимаю их использование.

Это то, что я имею до сих пор:

BaseModule

module BaseModule
    implicit none

    interface
        subroutine sub1(idx)
            implicit none
            integer, intent(in) :: idx
        end subroutine sub1

        subroutine sub2(idx)
            implicit none
            integer, intent(in) :: idx
        end subroutine sub2

        subroutine sub3(idx)
            implicit none
            integer, intent(in) :: idx
        end subroutine sub3    
    end interface
end module BaseModule

ChildModule1

submodule (BaseModule) ChildModule1
    implicit none

    type :: Child1
    contains
        module procedure :: sub1
        module procedure :: sub2
    end type

contains

    module subroutine sub1
        print*, "Child 1 - execute 'sub1' - idx = ", idx
    end subroutine sub1

    module subroutine sub2
        print*, "Child 1 - execute 'sub2' - idx = ", idx
    end subroutine sub2

end submodule ChildModule1

ChildModule2

submodule (BaseModule) ChildModule2
    implicit none

    type :: Child2
    contains
        module procedure :: sub1
        module procedure :: sub2
        module procedure :: sub3
    end type

contains

    module subroutine sub1
        print*, "Child 2 - execute 'sub1' - idx = ", idx
    end subroutine sub1

    module subroutine sub2
        print*, "Child 2 - execute 'sub2' - idx = ", idx
    end subroutine sub2

    module subroutine sub3
        print*, "Child 2 - execute 'sub3' - idx = ", idx
    end subroutine sub3

end submodule ChildModule2

тест

program test
    use ChildModule1
    use Childmodule2
    implicit none

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

    do idx = 1, 10

        !! Child1 outputs
        call c1%sub1(idx)
        call c1%sub2(idx)

        !! Child2 outputs
        call c1%sub1(idx)
        call c2%sub2(idx)
        call c1%sub3(idx)
    end do

end program test

Идея подмодулей заключается в том, что мне не нужно снова объявлять все inouts , но что, если я хочу использовать ту же подпрограмму (например, sub1) ) в нескольких подмодулях, где я объявляю разные типы? Прямо сейчас я получаю ошибку компиляции:

Error: MODULE PROCEDURE at (1) must be in a generic module interface

Ответы [ 2 ]

4 голосов
/ 07 марта 2019

Я попытаюсь очистить некоторые заблуждения, которые, я думаю, у вас есть о механизме субмодулей в Fortran.

Затем я хочу переопределить эти подпрограммы в серии дочерних модулей.

Вы не переопределяете процедур с подмодулями, вы реализуете их.

Идея, которую я понимаю субмодулей состоит в том, что мне не нужно снова объявлять все входы ,

Если под входами вы подразумеваете объявления и подписи процедуры(интерфейсы), тогда да , вам не нужно (но можно) повторить их в подмодулях, но нет , это не назначение субмодулей.

но что если я захочу использовать одну и ту же подпрограмму (например, sub1) в нескольких подмодулях, где я объявляю разные типы?

Ну, может, мне придетсякратко объясните, что такое подмодули, а какие нет.Для получения более подробной информации, пожалуйста, обратитесь к этой хорошей статье , написанной @SteveLionel, или к этой записи на вики-сайте Fortran, или к справке вашего компилятора (что бы это ни было)или даже в вашей любимой книге по Modern Fortran .

Как я уже говорил в еще один вопрос , подмодули - это функция, добавленная к языку для решения одного конкретного вопроса:разделение интерфейса и реализации.Основной мотивацией были каскады компиляции, генерируемые, когда вам нужно было изменить только детали реализации в модуле.

Подмодуль имеет доступ к сущностям в родительском модуле по ассоциации хоста, но родительский модуль не знает осуществование этого подмодуля.Когда вы объявляете тип Child1 внутри подмодуля ChildModule1, он доступен только внутри самого этого подмодуля, но не в родительском модуле BaseModule.

Кроме того, ChildModule1 не являетсямодуль и не может быть use d, как вы это делаете, в основной программе или любом другом программном модуле.Роль только подмодулей заключается в реализации module procedures, в котором отсутствует реализация в его родительском модуле.

Подведение итогов: разметка исходных файлов и программных модулей модульным, разумным способоми используйте подмодули , если имеет смысл , чтобы реализации ваших процедур были независимы от их объявлений (что-то вроде c заголовочных и исходных файлов ... но примите это сравнение с крошкой соли).


Редактировать:

Мне кажется, вы думаете, module и submodule в Фортране связаны с классами и подклассами в других языках. Они не! Может быть, это распространенное заблуждение, я не знаю.

Фортран имеет определяемые пользователем типы.Они могут связывать методы, конструкторы и деструкторы, они могут инкапсулировать данные, они могут быть расширены, они могут быть динамически отправлены, они могут быть объявлены абстрактными, они могут откладывать и переопределять члены.Это эквивалентно занятиям на других языках.Вы можете (и это хорошая практика) разделить каждый тип и связанный материал на соответствующие модули.Аналогично, вы можете иметь модуль для каждого типа расширения, если хотите.

Но, опять же, подмодули не имеют к этому никакого отношения.

0 голосов
/ 20 марта 2019

Чтобы подвести итог, я решил привести рабочий пример из того, что я пытался сделать.Еще раз спасибо @Rodrigo Rodrigues за разъяснение, что на самом деле являются подмодулями .Я не уверен, является ли этот подход правильным способом , но он работает для меня.

Задача

  • определитьтип с подпрограммой sub, который определен в Базовом классе
  • , определяет несколько дочерних типов, где sub переопределяется в соответствии с потребностями

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

module BaseClass

    implicit none

    type, abstract :: Base    ! <-- the base class with subroutine "sub"
    contains
        procedure(sub_interface), nopass, deferred :: sub
    end type

    interface
        subroutine sub_interface(i)    ! <-- the interface is defined here
            implicit none
            integer, intent(in) :: i
        end subroutine sub_interface
    end interface

end module BaseClass

Дочерний модуль

module ChildClass

    implicit none

    type, extends(Base) :: Child    ! <-- we extend the Base Class
    contains
        procedure, nopass :: sub
    end type

    interface
        module subroutine sub(i)    ! <-- the interface for the submodule (unfortunately we have to declare the entire thing again)
            implicit none
            integer, intent(in) :: i
        end subroutine sub
    end interface

end module ChildClass

Субмодуль

submodule (ChildClass) ChildSub

contains

    module procedure sub    ! <-- we finally get to define the subroutine
        print*, "The answer is :", i
    end procedure

end submodule

Программа

program test

    use ChildClass

    implicit none

    type(Child) :: c
    integer     :: i

    do i=1, 10
        call c%sub(i)
    end do

end program test

Теперь у нас может быть несколько дочерних классов , которые расширяют базовый класс и вызывают соответственно sub.Что мне лично не очень нравится, так это то, что мы должны объявить sub дважды, один раз в грани базового класса, а затем снова в интерфейсе дочернего класса, чтобы использовать подмодуль.Это повторение кода, но, возможно, это можно сделать лучше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...