重载不同类型及其基类
Overload for different types and their baseclass
假设我有一个抽象基础class Shape_t
,派生类型Rectangle_t
和Circle_t
。
两种派生类型都有一个通用函数 get_area
,我想为 class 重载它,以便我得到以下接口(朱利安式表示法):
get_area(type(Circle_t) :: C)
get_area(type(Rectangle_t) :: R)
! The following leads to ambiguous interfaces
get_area(class(Shape_t) :: S)
不幸的是,当我尝试此操作时出现 "ambiguous interface" 错误。
由此我有三个问题:
我想要实现的目标在概念上有什么错误吗?由于变量被显式声明为多态 (class(...)
),因此编译器始终可以选择最具体的接口并回退到多态接口。所以我没有看到歧义。
如果问题1的答案是:"There is no conceptional ambiguity"。标准中是否有更改此设置的计划?
下面的代码(其中引入了动态多态性 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 从通用接口中选择特定过程的规则,以及通用接口中的特定过程必须如何区分的规则,旨在易于学习和应用。为了避免需要任何描述 "best match"/"most specific" 是如何被选择的规则,在可能不明确的情况下,语言规则是这样的,最多可以有一个非基本过程并且在在任何作用域单元中最匹配的一个基本过程(仅当非基本特定不匹配时才考虑基本特定)。
您提出的程序违反了这些语言规则。
我还没有看到任何以会失去 "simple to learn and apply" 设计意图的方式更改规则的现实建议。
在每个类型中放置一个延迟绑定,指定一个函数来实现 get_area 的相关计算。从 get_shape 函数转发到该绑定(或将对 get_shape 的引用更改为对该绑定的引用)。避免使用 SELECT TYPE 实现特定于类型的行为 - 应使用绑定来实现特定于类型的行为。
假设我有一个抽象基础class Shape_t
,派生类型Rectangle_t
和Circle_t
。
两种派生类型都有一个通用函数 get_area
,我想为 class 重载它,以便我得到以下接口(朱利安式表示法):
get_area(type(Circle_t) :: C)
get_area(type(Rectangle_t) :: R)
! The following leads to ambiguous interfaces
get_area(class(Shape_t) :: S)
不幸的是,当我尝试此操作时出现 "ambiguous interface" 错误。 由此我有三个问题:
我想要实现的目标在概念上有什么错误吗?由于变量被显式声明为多态 (
class(...)
),因此编译器始终可以选择最具体的接口并回退到多态接口。所以我没有看到歧义。如果问题1的答案是:"There is no conceptional ambiguity"。标准中是否有更改此设置的计划?
下面的代码(其中引入了动态多态性
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 从通用接口中选择特定过程的规则,以及通用接口中的特定过程必须如何区分的规则,旨在易于学习和应用。为了避免需要任何描述 "best match"/"most specific" 是如何被选择的规则,在可能不明确的情况下,语言规则是这样的,最多可以有一个非基本过程并且在在任何作用域单元中最匹配的一个基本过程(仅当非基本特定不匹配时才考虑基本特定)。
您提出的程序违反了这些语言规则。
我还没有看到任何以会失去 "simple to learn and apply" 设计意图的方式更改规则的现实建议。
在每个类型中放置一个延迟绑定,指定一个函数来实现 get_area 的相关计算。从 get_shape 函数转发到该绑定(或将对 get_shape 的引用更改为对该绑定的引用)。避免使用 SELECT TYPE 实现特定于类型的行为 - 应使用绑定来实现特定于类型的行为。