如何在子模块Fortran中使用类型

问题描述 投票:0回答:2

我有一个基本模块,定义了一些子程序(sub1sub2sub3)。然后,我想在一系列子模块中覆盖这些子例程。

我知道如何使用单独的模块和延迟类型来做到这一点,但我决定尝试使用子模块。不幸的是,我不明白它们的用法。

这是我到目前为止:

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

oop module fortran
2个回答
4
投票

我将尝试清除一些我认为你对Fortran中的子模块机制的误解。

然后,我想在一系列子模块中覆盖这些子例程。

您不会使用子模块覆盖过程,而是实现它们。

我得到子模块的想法是我不必再次声明所有的输入,

如果通过inouts表示过程的声明和签名(接口),那么是的,你不需要(但可以)在子模块中重复它们,但不是,这不是子模块的目的。

但是如果我想在更多的子模块中使用相同的子程序(例如sub1)我会声明不同的类型呢?

好吧,也许我必须简要解释一下子模块是什么以及它们不是什么。有关更多详细信息,请参阅@SteveLionel撰写的this good article,或Fortran wiki上的this entry,或compiler's reference(无论是什么),甚至是您最喜爱的Modern Fortran上的书。

正如我在another question中所说,子模块是为语言添加的一个特性,用于解决一个特定问题:接口和实现的分离。主要动机是当您需要更改模块中的实现细节时生成的编译级联。

子模块可以通过主机关联访问父模块上的实体,但父模块不知道此子模块的存在。当您在子模块Child1中声明类型ChildModule1时,它只能在此子模块本身内访问,但不能在父模块BaseModule中访问。

此外,ChildModule1不是一个模块,并且不能像你想要做的那样在主程序或任何其他程序单元中使用used。子模块的唯一作用是实现在其父模块中缺少实现的module procedures

总结:以模块化,合理的方式布置源文件和程序单元,并使用子模块,如果有必要使程序的实现独立于它们的声明(类似于c头文件和源文件......但是请与一粒盐比较)。


编辑:

我发现你可能认为Fortran中的modulesubmodule与其他语言中的类和子类有关。他们没有!也许这是一个常见的误解,我不知道。

Fortran具有用户定义的类型。它们可以绑定方法,构造函数和析构函数,它们可以封装数据,可以扩展,可以动态调度,可以声明为抽象,可以推迟和覆盖成员。这相当于其他语言的类。您可以(并且这是一种很好的做法)将每种类型和相关的东西分成相应的模块。同样,如果需要,您可以为每种扩展类型创建一个模块。

但是,子模块再次与此无关。


0
投票

为了总结这一点,我决定从我试图做的事情中给出一个有效的例子。再次感谢@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,一次在基类的iterface中,然后再在子类的接口中声明,以便使用子模块。这是代码重复,但也许这可以做得更好。

© www.soinside.com 2019 - 2024. All rights reserved.