Interface Fortran-通用接口和特定接口之间的差异

Interface Fortran-通用接口和特定接口之间的差异,interface,fortran,Interface,Fortran,我试图理解抽象接口和“普通”接口之间的区别。什么使接口抽象?什么时候需要每一个 假设下面的例子 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 )

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

假设下面的例子

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
我在这里没有使用抽象接口。至少我认为我没有?我这样做已经有一段时间了,我从来没有在接口上使用过抽象的“限定符”。我似乎还没有发现需要使用抽象接口的情况

有人能给我点化一下吗

PS:编译器英特尔Visual Fortran Composer XE 2013 SP1更新3


编辑:

引用现代Fortran中的梅特卡夫、里德和科恩的话解释道:

在Fortran 95中,用 显式接口,需要使用接口块。这很好 对于单个过程,但对于声明多个 具有相同接口的过程(除了过程 姓名)。此外,在Fortran 2003中,有几种情况 在不可能的情况下(过程指针组件或 抽象类型绑定过程)

那么,我的编译器在接受下面的代码和上面的抽象类型代码时出错了吗

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关键字。我认为我的困惑源于这样一个事实,即编译器正在接受这样的代码。

标准中称为特定接口块的“正常”接口(正如您在问题标题中使用的那样)只是某些过程的正常接口块。因此:

interface
  subroutine foo_sub
  end subroutine
end interface
表示存在一个名为
foo_sub
的实际(外部)子例程,它符合指定的接口

抽象接口

abstract interface
  subroutine foo_sub_abs
  end subroutine
end interface
只指定某些过程的外观,但名称是接口的名称,而不是任何实际过程的名称。它可以用于程序指针

procedure(foo_sub_abs), pointer :: p
或者是一个伪参数

subroutine bar(f)
  procedure(foo_sub_abs) :: f
这意味着
p
将指向的实际过程或作为
f
传递的实际过程符合抽象接口

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


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

  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\u foo
的实际过程。有些编译器不诊断此问题,但它们可以


非常不相关的是通用接口。您可以识别它们,因为在单词
接口

  interface generic_sub
    procedure sub1

    subroutine sub2(...)
    end subroutine
  end interface
这里
sub1
sub2
都存在,
sub1
是已知的,并且已经有显式的接口可用,
sub2
是外部的,看起来像接口指定的那样,并且两者都是泛型
generic\u sub
的特定过程。这是完全不同的用法

然后你打电话

call generic_sub(...)

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

谢谢您,Vladmir。给我带来更多麻烦的例子实际上是抽象类型的例子。从概念上讲,我会说我在那里声明的接口是抽象的,但我从来没有这样声明过它们。这让我得出结论,我真的不知道它们是什么。现在,关于过程指针和过程伪参数。我也没有为这些声明抽象接口。你能给我举个例子吗?如果我不声明一个抽象接口,这个例子根本不起作用?(除了上面您已经说过编译器可以拒绝的那个)您从来都不严格需要抽象接口。您始终可以创建一个虚拟过程,并在
过程()
中指向它。因此,抽象界面主要是为了您的方便和语言的完整性。你能看一下并告诉我我的结论是否正确吗?另外,当您说“创建一个伪过程”时,您的意思是声明某种存根过程,它的显式接口将被使用吗?再次感谢您。是的,我所说的伪过程是指一个存根,它没有任何用处,但有正确的接口。@booNlatoT关于您的编辑,没有任何更改,您仍然有一个错误,因为不存在
foo_sub
,并且接口未声明为抽象。请注意,编译器不需要诊断此类问题,只允许它进行诊断。要更正代码,只需在单词
界面
之前添加单词
摘要