Inheritance 无法使用继承将数据和过程多态性混合使用
我最近尝试在代码中引入一些新的fortran 2003特性。基本上,我想混合使用数据和过程多态性。阅读了关于这些概念的基本教程(Fortran 2003中的面向对象编程) 第1部分:代码重用性:和 Fortran 2003中的面向对象编程 第2部分:数据多态性)我试图让我的基本概念发挥作用 我的想法是我有一个基本类型Inheritance 无法使用继承将数据和过程多态性混合使用,inheritance,fortran,polymorphism,Inheritance,Fortran,Polymorphism,我最近尝试在代码中引入一些新的fortran 2003特性。基本上,我想混合使用数据和过程多态性。阅读了关于这些概念的基本教程(Fortran 2003中的面向对象编程) 第1部分:代码重用性:和 Fortran 2003中的面向对象编程 第2部分:数据多态性)我试图让我的基本概念发挥作用 我的想法是我有一个基本类型交互,它有一个名称和一些类型绑定的过程。然后我有一些特定的交互,比如smallso2inv,它们通过一些参数扩展交互类型,并覆盖基本类型的类型绑定过程。现在我想传递基本类型的init
交互
,它有一个名称和一些类型绑定的过程。然后我有一些特定的交互,比如smallso2inv
,它们通过一些参数扩展交互类型,并覆盖基本类型的类型绑定过程。现在我想传递基本类型的initialize方法一个交互名称,如
call interaction%initialize("smallso2inv")
然后,内部指针specInteraction
应该指向类型smallso2inv
。现在使用时
call interaction%readInit()
我希望调用smallso2inv类型的readInit例程。这将使用计算所需的参数填充smallso2inv
类型
下面是我的交互模块的一个小的工作示例,它具有上述类型和我当前的实现:
module mod_interaction
implicit none
public
type interaction
character*80 :: name
class(interaction), pointer :: specInteraction => null()
procedure, pass(this) :: readInit
procedure, pass(this) :: readUpdate
procedure, pass(this) :: compute
procedure, pass(this) :: addToHamiltonian
procedure, pass(this) :: updateParameter
end type interaction
type, extends(interaction) :: smallso2inv
double precision :: uvalue, j1value, j2value
double precision :: uincr, j1incr, j2incr
contains
procedure, pass(this) :: setup => smallso2inv_initialize
procedure, pass(this) :: readInit => smallso2inv_readInit
procedure, pass(this) :: readUpdate => smallso2inv_readUpdate
procedure, pass(this) :: compute => smallso2inv_compute
procedure, pass(this) :: addToHamiltonian => smallso2inv_addToHamiltonian
procedure, pass(this) :: updateParameter => smallso2inv_updateParameter
end type smallso2inv
contains
subroutine initialize(this,name)
implicit none
type(interaction) :: this
character*80 :: name
class(interaction), allocatable, target :: thisInteraction
!
select case(name)
case('smallSO2inv')
allocate(smallso2inv::thisInteraction)
call thisInteraction%setup()
this%specInteraction => thisInteraction
end select
end subroutine initialize
subroutine smallso2inv_initialize(this)
!
class(smallso2inv) :: this
!
this%uvalue = 0.0d0
this%j1value = 0.0d0
this%j2value = 0.0d0
print*, "hallo smallso2inv init"
end subroutine smallso2inv_initialize
subroutine readInit (this)
class(interaction) :: this
character*80 :: name
call this%specInteraction%readInit()
end subroutine readInit
subroutine smallso2inv_readInit(this)
!
class(smallso2inv) :: this
!
print*, "hello smallso2inv readInit"
!
end subroutine smallso2inv_readInit
end module mod_interaction
我现在在使用ifort 15.0.0时遇到了两个错误
error #6437: A subroutine or function is calling itself recursively. [READINIT]
call this%specInteraction%readInit()
error #6460: This is not a field name that is defined in the encompassing structure. [SETUP]
call thisInteraction%setup()
我的实现似乎试图从基本的交互
类型调用子例程,而不是使用smallso2inv
类型。是否有一种方法可以解决此问题,而无需转到readInit
子例程中的case-type开关?我认为这应该是可能的,但不知何故,我认为我混淆了指针和变量的用法,因为我对多态上下文中指针的理解仍然有限。
提前感谢你的帮助 可能会有更多错误,但这是报告的错误: 初始化调用本身。它使用不同的对象实例调用它并不重要。它必须是递归的
recursive subroutine readInit (this)
class(interaction) :: this
call this%specInteraction%readInit()
end subroutine readInit
另一个错误是初始化错误。您需要使用select type
typeguard。在<代码>类型中,区域可以考虑<代码>此交互< /代码>具有新的非多态类型。您也可以改用类is
。我不确定这是否是一个明智的设计选择。我个人会选择两个单独的过程,可能是重载类型名的函数
subroutine initialize(this,name)
...
select case(name)
case('smallSO2inv')
allocate(smallso2inv::thisInteraction)
select case (thisInteraction)
type is (smallso2inv)
call thisInteraction%setup()
this%specInteraction => thisInteraction
end type
end select
end subroutine initialize
请注意,
字符*n
表示法非常过时,如果没有任何特殊的用户定义的赋值,没有理由使用=0.0d0
而不是简单的=0
。递归抱怨(在我看来)是一个编译器错误[1]。在一般情况下,编译器在编译时无法知道readInit绑定将分派到哪个特定过程,递归调用的限制是一个执行概念(即在运行时)。简单的解决方法是让步并添加递归属性
您只能访问声明的对象类型的绑定(和组件)。一个选项是用所需类型声明“临时”对象(注意,您有对象生存期问题,因此我将临时对象设为下面的指针),或者您可以使用Vladimir F建议的类似于结构构造函数的函数。对于简单构造,函数方法是典型的,但是,如果构造过程需要传回的不仅仅是构造对象(故障标志或类似),那么使用局部临时对象可能更合适
subroutine initialize(this,name)
implicit none
type(interaction) :: this
character(80) :: name
!
select case(name)
case('smallSO2inv')
block
! Local pointer of the required type.
type(smallso2inv), pointer :: thisInteraction
! Allocate an object of that type and point the pointer at it.
allocate(thisInteraction)
! Initialize the object.
call thisInteraction%setup()
! Save the pointer.
this%specInteraction => thisInteraction
end block
end select
...
这可能更像是一个样式问题,但是在上面,通过设置绑定调用smallso2inv\u initialize
过程没有实际意义,因为具有绑定的对象不是多态的(因此其动态类型和声明的类型是相同的)-您可以直接调用该过程
您还应该考虑组件和临时是否需要指针——如果组件未被用作引用,则使它们都可分配(使用MOVELYOLLC从临时转移到多态性组件)。
[1] :与此类似。实际上,此稍微更改的设置起作用(仅供浏览此问题的用户参考):
事实证明,Vladimir F answer对使我的初始化
例程工作非常有帮助,而IanH answer对使readInit
例程工作非常有帮助。对此解决方案的一些评论。这完全适用于ifort 15.0.0其他尚未测试的编译器specInteraction
必须是一个指针,如在ifort 15.0.0中,类型interaction
不能包含相同类型的可分配类(未实现的功能)。就像IanH所说的那样,readInit
必须是递归的,尽管在运行时调用了类型为smallso2inv
的正确对象,但编译器在编译时不知道它的类型。这也是类型绑定过程重载在这里很重要的原因,因为每个被调用的过程在编译时也必须在基类交互中找到。感谢你们两位的大力帮助。不要单独使用标签fortran2003
。它的订户非常少。通过阅读您的帖子,没有什么特别针对f2003的东西不在f2008中,所以我重新标记为fortran
谢谢您的评论。我会在以后的帖子里解释。我不明白你的答案。我需要有类(交互)::这个,因为传递的对象来自这个类型。我的想法是使用这个%specInteraction
来访问适当的基类型扩展(在本例中是smallso2inv)。请注意,没有子例程设置为过程,pass(this)::setup=>smallso2inv\u initialize
。我认为编译器忽略了分配(smallso2inv::thisInteraction)
这个%specInteraction=>thisInteraction
并坚持基本类型
module mod_interaction
implicit none
public
type interaction
character*80 :: name
class(interaction), pointer :: specInteraction => null()
procedure, pass(this) :: readInit
procedure, pass(this) :: readUpdate
procedure, pass(this) :: compute
procedure, pass(this) :: addToHamiltonian
procedure, pass(this) :: updateParameter
end type interaction
type, extends(interaction) :: smallso2inv
double precision :: uvalue, j1value, j2value
double precision :: uincr, j1incr, j2incr
contains
procedure, pass(this) :: initialize => smallso2inv_initialize
procedure, pass(this) :: readInit => smallso2inv_readInit
procedure, pass(this) :: readUpdate => smallso2inv_readUpdate
procedure, pass(this) :: compute => smallso2inv_compute
procedure, pass(this) :: addToHamiltonian => smallso2inv_addToHamiltonian
procedure, pass(this) :: updateParameter => smallso2inv_updateParameter
end type smallso2inv
contains
subroutine initialize(this,name)
!
implicit none
!
type(interaction) :: this
character*80 :: name
class(interaction),allocatable, target :: thisInteraction
!
this%name = name
select case(name)
case('smallSO2inv')
allocate(smallso2inv::thisInteraction)
select type (thisInteraction)
type is (smallso2inv)
call thisInteraction%initialize()
this%specInteraction => thisInteraction
end select
end select
!
!
end subroutine initialize
subroutine smallso2inv_initialize(this)
!
class(smallso2inv) :: this
!
this%uvalue = 0.0d0
this%j1value = 0.0d0
this%j2value = 0.0d0
print*, "hallo smallso2inv init"
end subroutine smallso2inv_initialize
recursive subroutine readInit (this)
class(interaction) :: this
class(interaction), allocatable :: thisInteraction
character*80 :: name
!
call this%specInteraction%readInit()
print*, "name=",this%name
!
end subroutine readInit
subroutine smallso2inv_readInit(this)
!
class(smallso2inv) :: this
!
print*, "hello smallso2inv readInit"
print*, "uvalue=",this%uvalue
!
end subroutine smallso2inv_readInit
end module mod_interaction