Fortran:从父级的类中分配子级时,调用父级的通用过程而不是子级

时间:2014-10-13 13:21:54

标签: oop generics inheritance fortran

我以一个例子的形式解释我的问题。

我有一个类型(location2d_t),其中包含两个成员xy以及一个类型绑定过程(calcdist2d)。除了(this)类(location2d_t)之外,该过程接受其自己的类型(作为第二个伪参数)来计算距离。 现在,我进一步将类型扩展为(location3d_t),其中也包含z

要重新定义过程,我无法覆盖前一个过程,因此我使用类型为(calcdist3d)的第二个参数创建一个新过程(location3d_t)并创建一个通用过程({ {1}})为他们。换句话说,第二个参数具有不同的类型,因此通用概念是适用的。

在更一般的范围内,让我们说主程序在这里,为了一般性我将我的对象声明为父类。当我使用子类型(calcdist)分配对象时,对第二个伪参数为(location3d_t)的调用(calcdist)引用父通用并且说

location3d_t

代码是

Error: Found no matching specific binding for the call to the GENERIC 'calcdist'

编译模块时没有任何错误。实现以下程序以使用模块:

module point_mod
implicit none
type location2d_t
    integer :: x,y
contains
    procedure :: calcdist2d => calcdistance2d
    procedure :: here => here_location2d
    generic   :: calcdist => calcdist2d 
end type

type, extends(location2d_t) :: location3d_t
    integer :: z
contains
    procedure :: calcdist3d => calcdistance3d
    procedure, public :: here => here_location3d
    generic, public   :: calcdist =>   calcdist3d 
end type        

contains

function calcdistance2d(this,location) result(output)
    class(location2d_t) :: this
    type(location2d_t)  :: location
    integer :: output
    output = int(sqrt(real((location%x-this%x)**2+(location%y-this%y)**2)))
end function

function calcdistance3d(this,location) result(output)
    class(location3d_t) :: this
    type(location3d_t) :: location
    integer :: output
    output = int(sqrt(real((location%x-this%x)**2+ &
    (location%y-this%y)**2+(location%z-this%z)**2)))
end function

subroutine here_location2d(this)
    class (location2d_t) :: this
    print*, "we are in locationd2d_t"
end subroutine

subroutine here_location3d(this)
    class (location3d_t) :: this
    print*, "we are in locationd3d_t"
end subroutine
end module

“Here”过程正确找到其动态类型。为什么不明确调用子(calcdist)的通用过程?即使在这种明显的情况下,我是否必须始终使用“选择类型”块? N.B。:我用GNU fortran 4.8和4.9以及ifort 14检查了代码。

2 个答案:

答案 0 :(得分:1)

是的,您必须使用"选择类型"。 "类型之外是"块,loc是多态的。仅在type is (location3d_t)内,loc具有类型,并且可以作为具有已定义类型的伪参数传递。

在扩展类型时,始终不会覆盖通用过程,因此在location3d_t中,calcdistcalcdist3dcalcdist2d以及loc的通用绑定在调用calcdist时需要特定类型才能找到合适的程序。

location2d_t被扩展到location3d_t时,here绑定被覆盖,并且只有一个过程与loc%here()相关联,因此可以在&#34}之外调用。类型是"阻止

答案 1 :(得分:0)

只需稍微调整一下calcdistanceXd函数,就可以在没有泛型的情况下完成此行为。您无法覆盖扩展类型中的函数的原因是location的参数类型不匹配。如果您将location中的calcdistance2d声明为class(location2d_t),则可以在calcdistance3d中对此进行匹配。您必须将select type构造添加到calcdistance3d,才能从多态变量location3d_t访问location的成员。

示例:

module point_mod
  implicit none

  type :: location2d_t
    integer :: x, y
  contains
    procedure, public, pass(this) :: calcdist => calcdistance2d
    procedure, public, pass(this) :: here => here_location2d
  end type

  type, extends(location2d_t) :: location3d_t
    integer :: z
  contains
    procedure, public, pass(this) :: calcdist => calcdistance3d
    procedure, public, pass(this) :: here => here_location3d
  end type
contains

  function calcdistance2d(this, location) result(output)
    class(location2d_t) :: this
    class(location2d_t)  :: location
    integer :: output
        output = int(sqrt(real((location%x-this%x)**2+(location%y-this%y)**2)))
  end function

  function calcdistance3d(this,location) result(output)
    class(location3d_t) :: this
    class(location2d_t) :: location
    integer :: output
    select type (location)
      type is (location3d_t)
        output = int(sqrt(real((location%x-this%x)**2+ &
        (location%y-this%y)**2+(location%z-this%z)**2)))
      class default 
        output = -1
    end select
  end function

  subroutine here_location2d(this)
    class (location2d_t) :: this
    print*, "we are in locationd2d_t"
  end subroutine

  subroutine here_location3d(this)
    class (location3d_t) :: this
    print*, "we are in locationd3d_t"
  end subroutine
end module

使用此版本的point_mod,您的示例程序可以运行:

program main
  use point_mod
  implicit none
  class (location2d_t), allocatable :: loc
  type (location3d_t) :: dum

  allocate(location2d_t::loc)
  call loc%here() ! calls  location2d_t procedure

  deallocate(loc)

  allocate(location3d_t::loc)
  call loc%here() !correctly calls procedure of location3d_t 

  print*,loc%calcdist(dum) 

end program

这种方法确实需要select type,但它隐藏在模块实现中,而不是模块用户所需。