2

我有以下代码,其中包含抽象类型、继承类型和短程序,我在其中创建一个对象并将其存储在一个数组中。

module m
    implicit none

    type :: container
        class(a), allocatable :: item
    end type container

    type, abstract :: a
        integer, public :: num
    end type a

    type, extends(a) :: b
        integer, public :: num2
   end type b
end module m

program mwe
    use m

    implicit none

    class(a), allocatable :: o1
    class(container), allocatable :: arr(:)

    o1 = b(1, 2)

    allocate(arr(2))
    arr(1) = container(o1)

    select type(t => o1)
        type is(b)
        write(*,*) t%num, t%num2
    end select

    select type(t => arr(1)%item)
        type is(b)
        write(*,*) t%num, t%num2
    end select
end program mwe

问题是,输出看起来像这样:

       1           2
       1           0

可以看出,存储在数组中的相同变量使第二个变量无效。为什么会这样?是因为数组是 type a,它只包含第一个变量吗?

我正在用ifort version 18.0.3.

4

2 回答 2

3

我相信

arr(1) = container(o1)

Fortran 2008 无效。这是一个内在的赋值语句,但标准的第 7.2.1.2 节说

在内部赋值语句中,(1) 如果变量是多态的,它应该是可分配的,而不是 coarray。

据我所知,arr(1)它是多态的,但不可分配,因此符合标准的编译器应该发出错误并中止编译。

如果我的推理是正确的,英特尔 Fortran 编译器编译此代码的事实是一个编译器错误,应该向英特尔报告。

于 2018-06-08T09:43:39.550 回答
1

与成熟的答案一样,可以说程序的任何输出都是有效的。但是,我们可以对代码进行简单的修改以使其正确 Fortran。1 此答案与此修改版本有关。

我会将此称为意外输出并寻求编译器供应商的帮助。

使用具有多态可分配组件的结构构造函数是 Fortran 中的新领域之一。编译器可能需要一段时间才能赶上或正确完成。

我已经使用 Intel Fortran 18.0.2 测试了您的代码,并看到了相同的输出。

对于你的问题

是因为数组是 type a,它只包含第一个变量吗?

否:在select type具有输出的部分t是类型的非多态实体b

您可以通过避免使用结构构造函数来解决此问题:

arr(1)%item = o1

我还看到 18.0.2 之前的英特尔编译器仍然做了一些不同的事情。


1 与声明

    class(container), allocatable :: arr(:)

arr是多态的和可分配的。正如ripero 所指出的,这意味着arr(1)的元素arr是多态的。但是,作为数组元素,arr(1)它本身不是多态的,因此可能不在内部赋值语句的左侧。我们可以通过两种方式更改代码:提供定义的赋值,或者使代码arr不是多态的。在问题的代码中,似乎没有理由让容器多态,所以我会考虑

type(container), allocatable :: arr(:)

此外,正如对该问题的评论中所讨论的,如果您希望使用 gfortran 8 或更早版本来查看会发生什么,您还应该修改问题中的代码,以便派生类型container的定义出现在派生类型a

于 2018-06-08T09:13:11.447 回答