Fortran中可分配的继承派生类型数组

时间:2015-07-15 19:14:56

标签: arrays inheritance fortran allocation

我试图创建一组与一个对象共享继承的派生类型的全局可用可分配数组。 Fortran似乎并没有让这很容易。以下是我到目前为止的情况。

首先是带有可分配数组的派生类型和模块。

Module Environment
    use Entity_M
    type(Entity_C), dimenion(:), allocatable :: objects
End Module Environment

Module Entity_M
    type Entity_T
        integer :: id
        real*8 :: time
        real*8, dimension(3) :: currPos

        type(TrajectoryDatum), dimension(:), allocatable :: trajTable

    end type Entity_T

    type Entity_C
        class(Entity_T), pointer :: e
    end type Entity_C

    type, extends(Entity_T) :: Aircraft_T
        real*8 :: altitude
    end type Aircraft_T

    type, extends(Entity_T) :: Missile_T
        integer :: targetID
    end type Missile_T

End Module Entity

现在是主程序

Program Main

    use Initialization
    use Environment
    use Entity_M

    call simInit(3)
    write(*,*) objects%trajTable !<---- this does not persist

    call runSim()

End Program Main

带问题的代码

Module Initialization

    use Entity_M

    contains

    subroutine simInit(numOfObjects)

        integer, intent(in) :: numOfObjects

        call objectsInit(numOfObjects)
        call launchersInit()

    end subroutine simInit


    subroutine objectsInit(numOfObjects)

        use Environment

        integer, intent(in) :: numOfObjects

        !local
        type(Aircraft_T) :: aircraft
        integer :: i

        allocate(objects(numOfObjects)

        do i = 1, numOfObjects

            aircraft%trajTable = getTrajectoryData()

            call allocatePointer(objects(i)%e, aircraft)

        end do

    end subroutine objectsInit

    subroutine allocatePointer(c, t)

        class(Entity), pointer, intent(out) :: c
        type(Aircraft), target, intent(in) :: t

        c => t

    end subroutine allocatePointer

End Module Initialization

以上只是在没有编译器的计算机上编写的示例代码。我尽力而为,如果有拼写错误,他们很少。我尽力反映原始代码的结构。

问题是字段&#34;对象%trajTable&#34;在离开&#34; objectsInit&#34;之后返回到未定义的指针。子程序。其他值如time,id和currPos仍然是正确的。我怎么能纠正这个?

我正在使用Visual Studio 2012和Intel Visual Fortran 2015。

1 个答案:

答案 0 :(得分:2)

由于该程序有许多重叠的名称(如飞机和飞机,在Fortran中被认为是相同的),我附上了&#34; _t&#34;所有类型(例如,飞机到飞机等)和&#34; _m&#34;所有模块名称(例如,Entity to Entity_m)使程序工作(至少正式)。

更重要的是,正如@innoSPC上面评论的那样,type(Aircraft) :: aircraft是一个局部变量,所以我认为退出objectsInit()后与之关联的指针变得不确定。该代码适用于

call allocatePointer( objects( i )% e, aircraft )

替换为

allocate( objects( i )% e, source=aircraft )

以便为每个objects( i )% e提供一个独立的记忆,其中包含Aircraft_t的类型,并将飞机内容复制到其中。

编辑以下是我用于测试的最小示例。

Module Entity_m
    implicit none

    type Entity_t   !! base type                                                    
        integer :: trajTable( 2 )
    endtype

    type, extends(Entity_t) :: Aircraft_t
        real*8 :: altitude
    endtype

    type, extends(Entity_t) :: Missile_t  !! dangerous...
        integer :: targetID
    endtype

    type Entity_c   !! container type                                               
        class(Entity_t), pointer :: e
    endtype

    type(Entity_c), allocatable :: objects(:)

contains

    subroutine objectsInit( numObj )

        integer :: numObj

        !local                                                                      
        type(Aircraft_t) :: aircraft
        type(Missile_t)  :: missile
        integer :: i

        allocate( objects( numObj ) )

        do i = 1, numObj

            if ( mod( i, 2 ) == 1 ) then
                aircraft% trajTable(:) = i
                aircraft% altitude = 10.0d0 * i

                allocate( objects( i )% e, source= aircraft )
            else
                missile% trajTable(:) = 10000 * i
                missile% targetID = -100 * i

                allocate( objects( i )% e, source= missile )  !! missile loaded !!
            endif
        enddo

    endsubroutine

EndModule

Program Main
    use Entity_m

    call objectsInit( 3 )

    do i = 1, 3
        print *, objects( i )% e% trajTable(:)  !! access members of base type      

        select type ( t => objects( i )% e )    !! access members of derived type   
            type is ( Aircraft_t ) ; print *, t% altitude
            type is ( Missile_t )  ; print *, t% targetID
        endselect
    enddo

EndProgram