我以一个例子的形式解释我的问题。
我有一个类型(location2d_t),其中包含两个成员x
和y
以及一个类型绑定过程(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检查了代码。
答案 0 :(得分:1)
是的,您必须使用"选择类型"。 "类型之外是"块,loc
是多态的。仅在type is (location3d_t)
内,loc
具有类型,并且可以作为具有已定义类型的伪参数传递。
在扩展类型时,始终不会覆盖通用过程,因此在location3d_t
中,calcdist
是calcdist3d
和calcdist2d
以及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
,但它隐藏在模块实现中,而不是模块用户所需。