不同类型及其基类的重载

问题描述 投票:0回答:1

假设我有一个派生类型为Shape_tRectangle_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)

不幸的是,当我尝试此操作时,出现“模棱两可的界面”错误。由此我有三个问题:

  1. 我想要实现的目标在概念上有问题吗?由于变量被显式声明为多态(class(...)),因此编译器始终可以选择最特定的接口,然后退回到多态接口。所以我看不出模棱两可。

  2. 如果对问题1的回答是:“没有概念上的歧义”。标准中是否有计划对此进行更改?

  3. 以下代码是引入动态多态性的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 polymorphism overloading
1个回答
4
投票

Fortran从通用界面中选择特定过程以及通用界面中的特定过程必须如何区分的规则被设计为易于学习和应用。为了避免需要任何描述如何选择“最佳匹配” /“最具体”的规则,在可能会造成歧义的情况下,语言规则应使得最多可以有一个非基本过程,最多可以有一个在任何作用域内都匹配的基本过程(仅当非基本要素不匹配时才考虑基本要素)。

您建议的程序违反了这些语言规则。

我还没有看到任何现实的提议来改变规则,而这些规则会失去“简单学习和应用”的设计意图。

在每种类型中放置一个延迟绑定,以指定实现get_area的相关计算的函数。从get_shape函数转发到该绑定(或将对get_shape的引用更改为对该绑定的引用)。避免使用SELECT TYPE实现特定于类型的行为-应使用绑定来实现特定于类型的行为。

© www.soinside.com 2019 - 2024. All rights reserved.