假设我有一个派生类型为Shape_t
和Rectangle_t
的抽象基类Circle_t
。这两个派生类型都有一个通用函数get_area
,我也想为该类重载它,以便获得以下接口(Julianesque表示法):
get_area(type(Circle_t) :: C)
get_area(type(Rectangle_t) :: R)
! The following leads to ambiguous interfaces
get_area(class(Shape_t) :: S)
不幸的是,当我尝试此操作时,出现“模棱两可的界面”错误。由此我有三个问题:
我想要实现的目标在概念上有问题吗?由于变量被显式声明为多态(class(...)
),因此编译器始终可以选择最特定的接口,然后退回到多态接口。所以我看不出模棱两可。
如果对问题1的回答是:“没有概念上的歧义”。标准中是否有计划对此进行更改?
以下代码是引入动态多态性的dyn_get_area
的可靠解决方法吗?请注意,我想尽可能地坚持静态多态性,即只要在编译时知道具体的Shape即可。
module shapes_mod
implicit none
private
public :: Shape_t, Rectangle_t, Circle_t, PI, get_area, dyn_get_area
real, parameter :: PI = atan(1.0) * 4.0
type, abstract :: Shape_t
end type
type, extends(Shape_t) :: Circle_t
real :: r = 0.0
end type
type, extends(Shape_t) :: Rectangle_t
real :: a = 0.0, b = 0.0
end type
interface get_area
module procedure get_area_Rectangle_t, get_area_Circle_t
end interface
contains
pure function get_area_Circle_t(C) result(res)
type(Circle_t), intent(in) :: C
real :: res
res = C%r**2 * PI
end function
pure function get_area_Rectangle_t(R) result(res)
type(Rectangle_t), intent(in) :: R
real :: res
res = R%a * R%b
end function
pure function dyn_get_area(S) result(res)
class(Shape_t), intent(in) :: S
real :: res
select type(S)
type is(Rectangle_t)
res = get_area(S)
type is(Circle_t)
res = get_area(S)
end select
end function
end module
program test_polymorphic_and_static_overload
use shapes_mod, only: Shape_t, Rectangle_t, Circle_t, get_area, dyn_get_area
implicit none
class(Shape_t), allocatable :: random_shape
type(Circle_t) :: circle
type(Rectangle_t) :: rectangle
real :: p
circle = Circle_t(1.0)
rectangle = Rectangle_t(1.0, 2.0)
call random_number(p)
if (p < 0.5) then
random_shape = circle
else
random_shape = rectangle
end if
write(*, *) get_area(circle)
write(*, *) get_area(rectangle)
write(*, *) dyn_get_area(random_shape)
end program
Fortran从通用界面中选择特定过程以及通用界面中的特定过程必须如何区分的规则被设计为易于学习和应用。为了避免需要任何描述如何选择“最佳匹配” /“最具体”的规则,在可能会造成歧义的情况下,语言规则应使得最多可以有一个非基本过程,最多可以有一个在任何作用域内都匹配的基本过程(仅当非基本要素不匹配时才考虑基本要素)。
您建议的程序违反了这些语言规则。
我还没有看到任何现实的提议来改变规则,而这些规则会失去“简单学习和应用”的设计意图。
在每种类型中放置一个延迟绑定,以指定实现get_area的相关计算的函数。从get_shape函数转发到该绑定(或将对get_shape的引用更改为对该绑定的引用)。避免使用SELECT TYPE实现特定于类型的行为-应使用绑定来实现特定于类型的行为。