我正在尝试理解抽象接口和“普通”接口之间的区别。什么使界面抽象?每个人什么时候需要?
假设以下示例
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中的Metcalf,Reid和Cohen解释:
在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关键字。我认为我的困惑源于编译器接受这样的代码这一事实。
答案 0 :(得分:6)
“普通”接口 - 标准称为特定接口块(正如您在问题标题中使用的那样) - 只是某些过程的正常接口块。因此:
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_foo
的实际程序。有些编译器没有对此进行诊断,但他们可以。
非常不相关的是通用接口。您可以识别它们,因为在单词interface
interface generic_sub
procedure sub1
subroutine sub2(...)
end subroutine
end interface
这里sub1
和sub2
都存在,sub1
已经知道并且已经有明确的接口可用,sub2
是外部的,看起来像接口指定的那样,两者都是通用generic_sub
的具体程序。这是一个非常不同的用法。
然后致电
call generic_sub(...)
并根据您传递的参数,编译器选择调用哪个特定过程,如果它是sub1
或sub2
。