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

Allocatable Array of Inherited Derived Types Issues in Fortran

我正在尝试创建一组派生类型的全局可用可分配数组,这些派生类型与单个对象共享继承。 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

以上只是在没有编译器的计算机上编写的示例代码。我已尽力而为,希望即使有错别字也很少。我尽量模仿原代码的结构。

问题是字段 "objects%trajTable" 在离开 "objectsInit" 子例程后返回到未定义的指针。时间、id 和 currPos 等其他值仍然正确。我该如何纠正?

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

因为程序有很多重叠的名称(比如 Aircraft 和 aircraft,在 Fortran 中被认为是相同的),我在所有类型上都附加了“_t”(例如 Aircraft 到 Aircraft_t 等)和所有模块名称的“_m”(例如,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