Fortran的“抽象"与“抽象"的区别和“正常"接口 [英] Difference between Fortran's "abstract" and "normal" interfaces

查看:21
本文介绍了Fortran的“抽象"与“抽象"的区别和“正常"接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图理解抽象接口和普通"接口之间的区别.什么使接口抽象?什么时候需要每一个?

I'm trying to understand the difference between abstract interfaces and "normal" interfaces. What makes an interface abstract? When is each one necessary?

假设下面的例子

module abstract_type_mod
  implicit none

  type, abstract :: abstract_t
  contains
    procedure(abstract_foo), pass, deferred :: Foo
  end type

  interface
    subroutine abstract_foo ( this, a, b )
      import :: abstract_t
      implicit none
      class(abstract_t), intent(in)  :: this
      real,              intent(in)  :: a
      real,              intent(out) :: b
    end subroutine
  end interface

end module

module concrete_type_mod
  use abstract_type_mod
  implicit none

  type, extends ( abstract_t ) :: concrete_t
  contains
    procedure, pass :: Foo
  end type

  contains

  subroutine Foo ( this, a, b )
    implicit none
    class(concrete_t), intent(in)  :: this
    real,              intent(in)  :: a
    real,              intent(out) :: b

    b = 2 * a

  end subroutine
end module 

module ifaces_mod
  implicit none

  interface
    subroutine foo_sub ( a, b )
      implicit none
      real, intent(in)  :: a
      real, intent(out) :: b
    end subroutine
  end interface

end module

module subs_mod
  implicit none

  contains

  pure subroutine module_foo ( a, b )
    implicit none
    real, intent(in)  :: a
    real, intent(out) :: b

    b = 2 * a

  end subroutine

end module

program test
  use ifaces_mod
  use subs_mod
  use concrete_type_mod
  implicit none

  type(concrete_t) :: concrete
  procedure(foo_sub) :: external_sub
  procedure(foo_sub), pointer :: foo_ptr
  real :: b

  foo_ptr => external_sub

  call foo_ptr ( 0.0, b )
  print*, b

  foo_ptr => module_foo

  call foo_ptr ( 1.0, b )
  print*, b

  call concrete%Foo ( 1.0, b )
  print*, b

end program

pure subroutine external_sub ( a, b )
  implicit none
  real, intent(in)  :: a
  real, intent(out) :: b

  b = a + 5

end subroutine

输出是

5.000000
2.000000
2.000000

这里我没有使用抽象接口.至少我认为我没有?我已经这样做了一段时间,我从来没有在接口上使用过抽象的限定符".好像还没有发现需要使用抽象接口的情况.

I haven't used abstract interfaces here. At least I think I havent? I've been doing this for a while and I've never used the abstract "qualifier" on interfaces. It seems that I haven't found a case where using abstract interfaces is required.

有人可以在这里启发我吗?

Could someone enlighten me here?

PS:编译器 Intel Visual Fortran Composer XE 2013 SP1 更新 3.

PS: Compiler Intel Visual Fortran Composer XE 2013 SP1 Update 3.

<小时>

在现代 Fortran 中引用 Metcalf、Reid 和 Cohen 的解释:

Quoting Metcalf, Reid and Cohen in Modern Fortran Explained:

在 Fortran 95 中,用显式接口,需要使用接口块.这可以对于单个过程,但对于声明多个过程有点冗长具有相同接口的程序(除了程序名称).此外,在Fortran 2003中,有几种情况在这变得不可能的地方(过程指针组件或抽象类型绑定过程).

In Fortran 95, to declare a dummy or external procedure with an explicit interface, one needs to use an interface block. This is fine for a single procedure, but is somewhat verbose for declaring several procedures that have the same interface (apart from the procedure names). Furthermore, in Fortran 2003, there are several situations where this becomes impossible (procedure pointer components or abstract-type bound procedures).

那么,我的编译器是否错误地接受了下面的代码以及上面带有抽象类型的代码?

So, is my compiler in error for accepting the code below and also the one with abstract type above?

module ifaces_mod
  implicit none

  interface
    subroutine foo_sub ( a, b )
      implicit none
      real, intent(in)  :: a
      real, intent(out) :: b
    end subroutine
  end interface

end module

module my_type_mod
  use ifaces_mod
  implicit none

  type my_type_t
    procedure(foo_sub), nopass, pointer :: Foo => null()  
  end type

end module

在这两种情况下,我会说我实际上已经声明了抽象接口,而没有使用 abstract 关键字.我认为我的困惑源于编译器正在接受这样的代码.

In both cases, I'd say that I actually have declared abstract interfaces without using the abstract keyword. I think my confusion has roots on the fact that the compiler is accepting code like this.

推荐答案

普通"接口——被标准称为特定接口块(正如你在问题标题中所用的那样)——只是某些程序的普通接口块.因此:

The "normal" interfaces — known by the standard as specific interface blocks (as you use in the title of the question) — are just normal interface blocks for some procedure. Therefore:

interface
  subroutine foo_sub
  end subroutine
end interface

表示存在一个名为foo_sub的实际(外部)子程序并且它符合指定的接口.

means that there exists an actual (external) subroutine named foo_sub and it conforms to the specified interface.

抽象接口

abstract interface
  subroutine foo_sub_abs
  end subroutine
end interface

只是指定了一些过程的样子,但名称是接口的名称,而不是任何实际过程的名称.它可以用于过程指针

just specifies how some procedure may look like, but the name is the name of the interface, not of any actual procedure. It can be used for a procedure pointers

procedure(foo_sub_abs), pointer :: p

或用于虚拟参数

subroutine bar(f)
  procedure(foo_sub_abs) :: f

它意味着p将指向或作为f传递的实际过程符合抽象接口.

and it means that the actual procedure to which p will point or which is passed as f conforms to the abstract interface.

请注意,在前两个示例中,您可以使用某些现有过程而不是抽象接口.它只需要在作用域中有可用的显式接口(通常它在同一个模块中,或者在使用的模块中).

Note that you are allowed to use some existing procedure instead of an abstract interface in both two former examples. It just needs to have explicit interface available in the scope (typically it is in the same module, or in a module which is used).

据我所知(但请参阅下面@IanH 的评论)编译器可以拒绝您的代码:

As far as I know (but see @IanH's comment below) the compiler is allowed to refuse your code:

  interface
    subroutine abstract_foo ( this, a, b )
      import :: abstract_t
      implicit none
      class(abstract_t), intent(in)  :: this
      real,              intent(in)  :: a
      real,              intent(out) :: b
    end subroutine
  end interface

因为不存在名为 abstract_foo 的实际过程.一些编译器不诊断这个,但他们可以.

because there exists no actual procedure named abstract_foo. Some compilers do not diagnose this, but they could.

完全不相关的是通用接口.你可以认出它们,因为在interface

Quite unrelated are generic interfaces. You can recognize them, because there is a name of a generic procedure after the word interface

  interface generic_sub
    procedure sub1

    subroutine sub2(...)
    end subroutine
  end interface

这里 sub1sub2 都存在,sub1 已知并且已经有显式接口可用,sub2是外部的,看起来是接口指定的,都是通用generic_sub的具体过程.这是完全不同的用法.

Here sub1 and sub2 both exist, sub1 is already known and has already explicit interface available, sub2 is external and looks as the interface specifies, and both are specific procedure of the generic generic_sub. This is quite a different usage.

然后你打电话

call generic_sub(...)

并且根据您传递的参数,编译器选择调用哪个特定过程,如果它是sub1,或sub2.

and according to the arguments you pass, the compiler chooses which specific procedure is called, if it is sub1, or sub2.

这篇关于Fortran的“抽象"与“抽象"的区别和“正常"接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆