Heterogeneous array of Fortran classes

2019-07-13 01:26发布

问题:

I have an abstract type and several types which inherit from him. Now I need to make an array of instances of those inherited types, but I'm not sure, if it's even possible in Fortran.

I've tried to make some wrapper type, like in Creating heterogeneous arrays in Fortran.

module m
implicit none

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

type, extends(a) :: b
end type b

type, extends(a) :: c
end type c

type :: container
    class(*), allocatable :: ptr 
end type
end module m

program mwe 
use m

type(b) :: b_obj
class(*), allocatable :: a_arr(:)

b_obj = b(1)

allocate(container :: a_arr(3))
a_arr(1) = container(b_obj)

end program mwe 

But I'm getting this error:

test3.f90:28:25:

 a_arr(1) = container(b_obj)
                     1
Error: Can't convert TYPE(b) to CLASS(*) at (1)

What am I doing wrong? Or is there any other, correct way to do it?


Attempt 2

I edited the code accordingly to francescalus's answer:

program mwe 
use m

type(b) :: b_obj
type(c) :: c_obj
type(container), allocatable :: a_arr(:)
integer :: i

b_obj = b(1)
c_obj = c(2)

allocate(container :: a_arr(3))
a_arr(1)%ptr = b(1)
a_arr(2)%ptr = c(3)
a_arr(3)%ptr = c(1000)

do i=1,3
    write(*,*) a_arr(i)%ptr%num
end do

end program mwe 

And I'm getting another error:

test3.f90:36:35:

     write(*,*) a_arr(i)%ptr%num
                               1
Error: ‘num’ at (1) is not a member of the ‘__class__STAR_a’ structure

回答1:

As IanH commented when outlining the approach you take, the then current version of gfortran

does not appear to support definition of an unlimited polymorphic component via a structure constructor

container(b_obj) is such a thing. So, leaving aside whether you are still coming up against this problem, one may be interested in still allowing older versions/other compilers to use the code.

An alternative approach is not to use a constructor for the element of your container. Instead the single component can feature directly in an assignment:

use m
type(container) a_arr(3)  ! Not polymorphic...
a_arr%ptr = b(1)          ! ... so it has component ptr in its declared type
end mwe

Naturally, we still have the component of the container type polymorphic so any attempts to reference/define/etc., that component will be subject to those various restrictions. In your question you have the component unlimited polymorphic, but I see that you first talk about restricting the container's consideration to elements which extend the first type. Rather than declaring the container component as unlimited polymorphic it could be much more helpfully of declared type a:

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

This would be sufficient to solve the problem with

do i=1,3
    write(*,*) a_arr(i)%ptr%num
end do

because num is a component of the declared type of a_arr(i)%ptr (that is., a). In general, it isn't the complete solution because

do i=1,3
    write(*,*) a_arr(i)%ptr%num_of_type_b
end do

wouldn't work (with num_of_type_b a component in the extending type). Here you have to use the usual tricks (defined input/output, dynamic resolution, select type and so on). Those are beyond the scope of this answer and many other questions may be found covering them.