Fortran的“抽象"与“抽象"的区别和“正常"接口 [英] Difference between Fortran's "abstract" and "normal" interfaces
问题描述
我试图理解抽象接口和普通"接口之间的区别.什么使接口抽象?什么时候需要每一个?
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
这里 sub1
和 sub2
都存在,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屋!