我有以下代码,具有抽象类型,继承类型和短程序,我在其中创建一个对象并将其存储在数组中。
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
可以看出,存储在数组中的同一变量将第二个变量取消。为什么会这样?是因为数组的类型是a
,它只包含第一个变量吗?
我正在使用ifort version 18.0.3
编译代码。
我相信
arr(1) = container(o1)
无效的 Fortran 2008。 这是一个内在赋值语句,但标准的第 7.2.1.2 节说
在内在赋值语句中,(1( 如果变量是多态的,它应该是可分配的,而不是协数组。
据我所知,arr(1)
是多态的,但不可分配,因此符合标准的编译器应该发出错误并中止编译。
如果我的推理是正确的,那么英特尔 Fortran 编译器编译此代码的事实是一个编译器错误,应报告给英特尔。
与ripero的答案一样,可以说该程序的任何输出都是有效的。 但是,我们可以对代码进行简单的修改以使其正确 Fortran。1这个答案与这个修改后的版本有关。
我会调用此意外输出并寻求编译器供应商的帮助。
使用具有多态可分配组件的结构构造函数是 Fortran 中的新领域之一。 编译器可能需要一段时间才能赶上或正确完成。
我已经使用英特尔 Fortran 18.0.2 测试了您的代码,并看到了相同的输出。
对于您的问题
是因为数组的类型是
a
,它只包含第一个变量吗?
否:在具有输出t
的select type
部分中是类型为b
的非多态实体。
您可以通过避免使用结构构造函数来解决此问题:
arr(1)%item = o1
我还看到 18.0.2 之前的英特尔编译器仍然做一些不同的事情。
1附声明
class(container), allocatable :: arr(:)
arr
是多态和可分配的。 正如里佩罗所指出的,这意味着arr(1)
,arr
的元素是多态的。 但是,作为数组元素,arr(1)
本身不是多态的,因此可能不在内部赋值语句的左侧。 我们可以通过两种方式更改代码:提供定义的赋值,或者使arr
非多态。 在问题的代码中,似乎没有理由让容器多态,所以我会考虑
type(container), allocatable :: arr(:)
此外,正如在对该问题的评论中所讨论的,如果您希望使用 gfortran 8 或更早版本来查看会发生什么,您还应该修改问题中的代码,以便派生类型的定义container
位于派生类型的定义之后a
。