【问题标题】:FORTRAN: data polymorphicFORTRAN:数据多态
【发布时间】:2014-09-23 16:58:41
【问题描述】:

我试图隐藏真实数据类型和复杂数据类型之间的区别。在 FORTRAN 2003 中,我认为有办法做到这一点。

目标是定义一个多态可分配数组,其类型可以在运行时决定。另外还有一个子程序可以用多态数组来做一些代数(同样的方程适用于真实和复杂的数据)。

为了做到这一点,我做了两次尝试:

方法 A:

module poly
    implicit none
    private
    type, abstract, public :: MyType
    contains
        procedure, public :: Constructor
    endtype MyType

    type, extends(MyType), public :: MyTypeR
        real(8), allocatable :: AllData(:)
    endtype MyTypeR

    type, extends(MyType), public :: MyTypeI
        complex(8), allocatable :: AllData(:)
    endtype MyTypeI

    contains

    subroutine Constructor(this, Nsize)
        class(MyType), intent(inout) :: this
        integer, intent(in) :: Nsize
        select type(this)
        type is(MyTypeR)
            allocate(this%AllData(Nsize))        
        type is(MyTypeI)
            allocate(this%AllData(Nsize))  
        endselect
    endsubroutine
endmodule poly

! Algebra subroutine
module Operation
    contains
    subroutine Square(Array)
        class(*), intent(inout) :: Array(:)
        select type(Array)
        class is(real(8))
            Array = Array**2
        class is(complex(8))
            Array = Array**2
        endselect
    endsubroutine Square
endmodule Operation

! Main
program test
    use poly
    use Operation
    class(MyType), allocatable :: t1, t2
    integer :: i
    logical :: IfComplex = .true.

    if(IfComplex) then
        allocate(MyTypeI::t1)
    else
        allocate(MyTypeR::t1)
    endif
    call t1%Constructor(4)
    call Square(t1%AllData)
endprogram test

方法B(无限多态可分配变量):

module poly
    implicit none
    private
    type, public :: MyType
        class(*), allocatable :: AllData(:)
    contains
        procedure, public :: Constructor
    endtype MyType

    contains

    subroutine Constructor(this, Nsize, IfComplex)
        class(MyType), intent(inout) :: this
        integer, intent(in) :: Nsize
        logical, intent(in) :: IfComplex
        if(IfComplex) then
            allocate(complex(8)::this%AllData(Nsize))        
        else
            allocate(real(8)::this%AllData(Nsize))  
        endif
    endsubroutine
endmodule poly

! Same algebra subroutine
! Main
program test
    use poly
    use Operation
    type(MyType) :: t1, t2
    integer :: i
    call t1%Constructor(4, .true.)
    call Square(t1%AllData)
endprogram test

那么我在这两种方法中的代数子例程都有问题:在内部赋值语句中,变量不应是多态的。任何建议将不胜感激。

【问题讨论】:

    标签: polymorphism fortran runtime fortran2003


    【解决方案1】:

    有一些问题。

    在当前的 Fortran 中,您不能扩展内在类型 - 内在类型不能出现在派生类型定义的 EXTENDS 说明符中。

    因此,在 Fortran 2008 中,该语言禁止在选择类型构造中假装内在类型可以是祖先类型。这种禁止隐含在类型保护语句的语法规则中(TYPE IS...CLASS IS 等 - type-guard-stmt 的 CLASS IS 形式明确限制为 派生的-type-spec,它不包括使用内在类型名称),这意味着符合 Fortran 2008 的编译器应该为您的语法发出错误消息。

    (在发布的 Fortran 2003 中不存在该限制,但在后来的 Fortran 2003 勘误中添加了它 - 也许您的 Fortran 2003 编译器供应商还没有开始实施它。)

    在 Fortran 2003 中,当分配给的变量(等号左侧的东西)是多态的时,不允许内部分配。分配给多态变量的能力是 Fortran 2008 中添加到语言中的一项功能。

    上述两个问题的解决方案是在您的Square 子例程 TYPE IS 而不是 CLASS IS 中创建类型保护语句。

    除了眼前的问题(以下内容更主观,取决于您最终打算做什么):

    • 在第一个示例中,更典型的安排是有两个单独的非类型绑定构造函数过程,一个用于 MyTypeR,一个用于 MyTypeI。然后,代数运算将是 MyType 父级的延迟绑定,然后扩展会适当地实现它。

    • 第二个示例中的 MyType 并没有真正发挥有用的作用 - 您还不如直接使用可分配的无限多态对象。

    【讨论】:

    • 很好的答案。如果允许内部函数支持(包括赋值),那将是一个很棒的特性。
    • 非常感谢您对我的两种方法的建议。编译问题就解决了。假设我目前只处理 real(8) 和 complex(8) (在第二种方法中我确实省略了一些细节)。您认为哪种方法更好?
    猜你喜欢
    • 2015-02-21
    • 2019-04-24
    • 1970-01-01
    • 2022-11-14
    • 2012-07-19
    • 1970-01-01
    • 2015-09-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多