首页 > 解决方案 > 如何在 Fortran 中使用多态数据类型作为另一种数据类型的属性

问题描述

我创建了一个名为“元素”的类,它有几个属性和类型绑定的过程。其中一个属性是具有两个继承类型“kin1”和“kin2”的抽象类类型“kin”。我希望能够在运行时根据输入使用构造函数将“kin1”或“kin2”作为属性分配给对象“元素”。目标是有一个元素列表,每个元素的 element%kin 要么是“kin1”类型,要么是“kin2”类型。

模块元素

模块元素

使用亲属

implicit none

type,public :: element_type
    class(kin_type),allocatable :: kin
contains
    procedure,pass(this), private :: set_kin
    procedure,pass(this), public  :: get_kin
end type element_type

interface element_type
    module procedure element_type_constructor
end interface element_type 

包含

type (element_type) function element_type_constructor(kin)
    implicit none             
    class(kin_type),allocatable,  intent (in) :: kin    
    call element_type_constructor%set_kin(kin)
end function element_type_constructor

! my try of set_kin
subroutine set_kin(this,kin)
implicit none
class(element_type), intent(inout) :: this
class(kin_type),allocatable, intent(in) :: kin
this%kin = kin
end subroutine

端模块元件

模块亲属

模块 kin 隐式 无 私有

type,abstract :: kin_type
end type kin_type

type,public, extends(kin_type) :: kin1_type
    private
    integer :: data1
contains
    procedure,pass(this),private :: set_data1
    procedure,pass(this),public  :: get_data1
    procedure,pass(this),public  :: print =>print_kin1
end type kin1_type

type,public, extends(kin1_type) :: kin2_type
    private
    real :: data2
contains
    procedure,pass(this),private :: set_data2
    procedure,pass(this),public  :: get_data2
    procedure,pass(this),public  :: print =>print_kin2
end type kin2_type

! constructor interface kin1_type
interface kin1_type
    module procedure kin1_type_constructor
end interface kin1_type

! constructor interface kin2_type
interface kin2_type
    module procedure kin2_type_constructor
end interface kin2_type

包含

! constructor kin1_type
type (kin1_type) function kin1_type_constructor(data1)
    implicit none
    integer,          intent (in) :: data1                
    class(kin1_type), intent (in) :: kin    
    call kin1_type_constructor%set_data1(data1)
end function kin1_type_constructor

! constructor kin2_type
type (kin2_type) function kin1_type_constructor(data1,data2)
    implicit none
    integer,          intent (in) :: data1 
    real,             intent (in) :: data2               
    class(kin2_type), intent (in) :: kin    
    call kin2_type_constructor%set_data1(data1)
    call kin2_type_constructor%set_data2(data2)
end function kin2_type_constructor


! Example of set subroutine
subroutine set_data1(this,data1)
    class(kin1_type),intent(inout) :: this    
    integer,         intent(in)    :: data1
    this%data1 = data1
end subroutine set_data1 

!其他手续...

端模块kin

程序

程序测试

use element
use kin

implicit none
type(element_type) :: thisElement
type(kin1_type)    :: thisKin1

! constructor for thisKin1
thisKin1 = kin1_constructor(data1 = 1)

! constructor for thisElement
thisElement = element_type_constructor(kin = thisKin1)

! Check kin structure and values
call thisElement%kin%print

结束程序

错误

我在 element_type_constructor 子例程运行期间收到以下错误:程序收到信号 SIGSEGV:分段错误 - 内存引用无效。

标签: oopfortran2008

解决方案


我还不能发表评论,所以这是第一个答案:不幸的是,提供的代码不完整。此外,缺少编译器的供应商和版本,这使得很难猜测实际问题是什么。

“修复”代码以获取以下示例表明它原则上是有效的:

kin.f90:

module kin
    implicit none
    private

    type,abstract,public :: kin_type
    contains
        procedure(print_iface), deferred :: print
    end type kin_type

    type,public, extends(kin_type) :: kin1_type
        private
        integer :: data1
    contains
        procedure,pass(this),private :: set_data1
        procedure,pass(this),public :: print => print_kin1
    end type kin1_type

    ! constructor interface kin1_type
    interface kin1_type
        module procedure kin1_type_constructor
    end interface kin1_type

    abstract interface
        subroutine print_iface(this)
            import kin_type
            class(kin_type), intent(in) :: this
        end subroutine
    end interface
contains

    ! constructor kin1_type
    type (kin1_type) function kin1_type_constructor(data1)
        implicit none
        integer,          intent (in) :: data1
        call kin1_type_constructor%set_data1(data1)
    end function kin1_type_constructor

    ! Example of set subroutine
    subroutine set_data1(this,data1)
    class(kin1_type),intent(inout) :: this
        integer,         intent(in)    :: data1
        this%data1 = data1
    end subroutine set_data1

    subroutine print_kin1(this)
        class(kin1_type),intent(in) :: this
        print *, this%data1
    end subroutine print_kin1

end module kin

元素.f90:

module element
    use kin, only: kin_type

    implicit none

    type,public :: element_type
        class(kin_type), allocatable :: kin
    contains
        procedure,pass(this), private :: set_kin
    end type element_type

    interface element_type
        module procedure element_type_constructor
    end interface element_type
contains

    type (element_type) function element_type_constructor(kin)
        implicit none
        class(kin_type), intent (in) :: kin
        call element_type_constructor%set_kin(kin)
    end function element_type_constructor

    ! my try of set_kin
    subroutine set_kin(this,kin)
        implicit none
        class(element_type), intent(inout) :: this
        class(kin_type), intent(in) :: kin
        this%kin = kin
    end subroutine
end module element

main.f90:

program test

    use element
    use kin

    implicit none
    type(element_type) :: thisElement
    class(kin_type), allocatable :: thisKin1

    ! constructor for thisKin1
    thisKin1 = kin1_type(data1 = 1)

    ! constructor for thisElement
    thisElement = element_type(kin = thisKin1)

    call thisElement%kin%print()
end program

使用 gfortran 7.4.0 构建它并运行它会产生:

$ gfortran -o prog kin.f90 element.f90 main.f90
$ ./prog 
           1
$

与所提供内容的一个显着区别是抽象类型上的延迟print过程,因为它是通过定义为 a 的属性调用的class(kin_type)。不幸的是,这并不能解释引用的错误。


推荐阅读