interface - fortran选择按过程调用派生类型

标签 interface module fortran polymorphism overloading

有没有办法使派生类型具有接口(interface),以便为泛型派生类型调用特定的模块过程?我可能没有正确解释这一点,但这里有一个简短的示例代码,说明了我想要做的事情:

  module test_mod
  implicit none

  private
  public :: type_AB ! This is what I'd like to do...
  public :: init,apply,delete

  interface type_AB ! This is what I'd like to do...
  module type type_AB
  end interface

  interface init;    module procedure init_A;      end interface
  interface init;    module procedure init_B;      end interface
  interface apply;   module procedure apply_A;     end interface
  interface apply;   module procedure apply_B;     end interface

  type type_A
    integer :: x
  end type

  type type_B
    integer,dimension(3) :: x
  end type

  contains

  subroutine init_A(AB,x)
    implicit none
    type(type_A),intent(inout) :: AB
    integer,intent(in) :: x
    AB%x = x
  end subroutine

  subroutine init_B(AB,x)
    implicit none
    type(type_B),intent(inout) :: AB
    integer,dimension(3),intent(in) :: x
    AB%x = 2
  end subroutine

  subroutine apply_A(AB,x)
    implicit none
    type(type_A),intent(inout) :: AB
    integer,intent(in) :: x
    AB%x = AB%x + x
  end subroutine

  subroutine apply_B(AB,x)
    implicit none
    type(type_B),intent(inout) :: AB
    integer,dimension(3),intent(in) :: x
    AB%x = AB%x + x
  end subroutine

  end module

在使用test_mod时,我可以简单地使用type_ab而不是指定type_a或type_b。我知道我可以只指定两个对象,但除了等级之外,它们基本上是相同的,因此最好有一种组合/多态对象,但我不想在其中嵌入第二个派生类型一。例如:

 type type_AB
   type(type_A) :: A
   type(type_B) :: B
 end type

因为它会使类文件更加困惑(引用X变为,例如AB%A%X而不是AB%X,如果AB是类型type_ab的AB)。如果这是唯一的方法,那么我想我可以做到这一点,但是我想知道是否还有其他选择。另外,使用组合/多态方法增加了需要在type_a内部处理任何内容的烦恼,如果使用了type_a,反之亦然。

我想其他人可能会以一种更好的方式提出这一点,但是当我研究示例时,大多数人似乎使用了F2003标准,我对此有些不熟悉。非常感谢您对回答或改进问题的任何帮助,谢谢。

更新:

我尝试实现该类型按建议扩展,但这是我所能获得的。

module type_AB_mod
implicit none
private
public :: type_AB ! This is what I'd like to do...
public :: init
interface init;    module procedure init_A;      end interface
interface init;    module procedure init_B;      end interface
type type_AB
  logical :: L
end type
type, extends(type_AB) :: type_A
  integer :: x
end type
type, extends(type_AB) :: type_B
  integer,dimension(3) :: x
end type
contains
subroutine init_A(AB,x)
  implicit none
  type(type_A),intent(inout) :: AB
  integer,intent(in) :: x
  AB%x = x
  write(*,*) 'Init A'
end subroutine
subroutine init_B(AB,x)
  implicit none
  type(type_B),intent(inout) :: AB
  integer,dimension(3),intent(in) :: x
  AB%x = 2
  write(*,*) 'Init B'
end subroutine
end module
program test
use type_AB_mod
implicit none
type(type_AB) :: AB
integer :: i
integer,dimension(3) :: j
call init(AB,i)
call init(AB,j)
end program

我有两个错误,这两个都是:

 There is no specific subroutine for the generic 'init'

引用调用init(ab,i)调用init(ab,j)

更新2:

我已经调整了示例以包括提供的答案:

  module type_AB_mod
  implicit none
  private
  public :: type_AB ! This is what I'd like to do...
  public :: init
  interface init;    module procedure init_A;      end interface
  interface init;    module procedure init_B;      end interface
  type type_AB
  end type
  type, extends(type_AB) :: type_A
    integer :: x
  end type
  type, extends(type_AB) :: type_B
    integer,dimension(3) :: x
  end type
  contains
  subroutine init_A(AB,x)
    implicit none
    type(type_AB),allocatable,intent(inout) :: AB
    integer,intent(in) :: x
    allocate(AB, source=type_A(x=x))
    write(*,*) 'Init A'
  end subroutine
  subroutine init_B(AB,x)
    implicit none
    type(type_AB),allocatable,intent(inout) :: AB
    integer,dimension(3),intent(in) :: x
    allocate(AB, source=type_B(x=x))
    write(*,*) 'Init B'
  end subroutine
  end module
  program test
  use type_AB_mod
  implicit none
  class(type_AB),allocatable :: AB
  integer :: i
  integer,dimension(3) :: j
  call init(AB,i)
  deallocate(AB)
  call init(AB,j)
  deallocate(AB)
  end program

,但我仍然得到编译器错误:

  allocate(AB, source=type_B(x=x))
           1          2
  Error: Type of entity at (1) is type incompatible with source-expr at (2):
  allocate(AB, source=type_A(x=x))
           1          2
  Error: Type of entity at (1) is type incompatible with source-expr at (2):

最佳答案

AB 的类型为 type_AB,通用 init 的特定过程适用于类型 type_Atype_B。所以确实没有匹配。

您表明您希望了解多态方法,以便主程序中的所有内容都基于 type_AB

通过多态性,变量具有声明动态类型。可以是 type_Atype_B 的变量将声明类型 type_AB 和动态类型,以当时合适的为准。

我们将这样一个变量声明为已声明类型 type_AB

class(type_AB), allocatable :: AB    ! Or POINTER

我们可以通过

将其设置为动态类型type_A
allocate (type_A :: AB)

(和 type_B 已作必要修改)。

这导致了通用解决方案。我们仍然消除了参数x的等级的歧义,但是两个特定的过程都声明了类型type_AB(毕竟,您想要设置基于变量的动态类型)在另一个参数上,所以它不能用来消除歧义)。

subroutine init_A(AB,x)
  class(type_AB), allocatable, intent(out) :: AB
  integer, intent(in) :: x
end subroutine

subroutine init_B(AB,x)
  class(type_AB), allocatable, intent(out) :: AB
  integer, intent(in) :: x(3)
end subroutine

这些都不含糊。剩下的就是在每个子例程中建立参数 AB 的动态类型和值。

为了清楚起见,我假设 type_AB 没有组件 L。您可以稍后对此进行必要的修改。

在每个子例程中使用内部赋值,例如

 AB = type_A(x=x)

 AB = type_B(x=x)

将处理动态类型和值。

但是,并非所有当前编译器都支持此功能,因此您还有其他选择

 allocate(AB, source=type_A(x=x))

 allocate(type_A :: AB)
 ! ... setting the component AB%x is not trivial, but outside scope of answer

调用适当的特定子例程后,程序中AB的动态类型符合预期。

它使用上面的 type_Atype_B 构造函数,其中使用了删除组件 L 的简化。这是在更一般的情况下应该注意的地方。

最后,我说“type_Atype_B”,声明类型 type_AB 的变量也可以具有动态类型 类型_AB。使其成为抽象类型消除了这种可能性。

关于interface - fortran选择按过程调用派生类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34146175/

相关文章:

arrays - 如何让函数返回从索引 0 开始的数组

C# 隐藏继承成员

没有模板函数继承的 C++ 接口(interface)

function - 如何从 C# 调用 ms-access 函数?

javascript - NodeJS 中未定义模块

performance - 有什么办法可以避免这些嵌套循环吗?

fortran - 在 Fortran 中是否有一种简短、可移植的方法来指定 "kind"?

c# - 使用接口(interface)引用变量调用基类方法

java - 为什么不同的谓词接口(interface)n JAVA 8?

perl - Perl 包/模块的返回值处理