我可以在Fortran中模拟多个传递的对象伪参数吗?
我想写一个接受两个传递的对象伪参数的过程,例如我可以在Fortran中模拟多个传递的对象伪参数吗?,fortran,polymorphism,Fortran,Polymorphism,我想写一个接受两个传递的对象伪参数的过程,例如 module m type, abstract :: Parent contains procedure(f_Parent), deferred :: f end type abstract interface subroutine f_Parent(foo,bar) import Parent implicit none class(Parent), intent(in) ::
module m
type, abstract :: Parent
contains
procedure(f_Parent), deferred :: f
end type
abstract interface
subroutine f_Parent(foo,bar)
import Parent
implicit none
class(Parent), intent(in) :: foo
class(Parent), intent(in) :: bar
end subroutine
end interface
type, extends(Parent) :: Child
contains
procedure, public :: f => f_Child
end type
contains
subroutine f_Child(foo,bar)
implicit none
class(Child), intent(in) :: foo
class(Child), intent(in) :: bar
end subroutine
end module
但是Fortran标准不允许这样做,因为bar
不是传递的对象伪参数,因此必须是class(Parent)
而不是class(Child)
我目前的解决办法是
subroutine f_Child(foo,bar)
implicit none
class(Child), intent(in) :: foo
class(Parent), intent(in) :: bar
select type(bar); type is(Child)
end select
end subroutine
这是可行的,但是select type
构造太慢了,并且主导了我的代码的运行时(这个子例程被调用了很多次)
我曾尝试使用一个传递的对象参数,该参数同时包含foo
和bar
,例如作为数组或指针,但这也是标准所禁止的
是否有任何方法可以模拟具有多个传递的对象伪参数的行为,而这些伪参数不会产生
select type
构造的成本?或者是从class(Parent)
获取class(Child)
参数的一种更快的方法?您可以使用单个分派两次:
Module m
Implicit None
Type, Public, Abstract :: Parent
Contains
Procedure( i_Parent_Parent ), Public , Deferred :: f
Procedure( i_Child_Parent ), Pass( bar ), Private, Deferred :: f_c_p
Procedure( i_set ), Public , Deferred :: set
End Type Parent
Type, Public, Extends( Parent ) :: Child
Integer , Private :: data
Contains
Procedure , Public :: f => f_Child_Parent
Procedure, Pass( bar ), Private :: f_c_p => f_Child_Child
Procedure , Public :: set => f_Child_set
End Type Child
Private
Abstract Interface
Subroutine i_Parent_Parent( foo, bar )
Import :: Parent
Implicit None
Class( Parent ), Intent( In ) :: foo
Class( Parent ), Intent( In ) :: bar
End Subroutine i_Parent_Parent
Subroutine i_Child_Parent( foo, bar )
Import :: Parent, Child
Implicit None
Class( Child ), Intent( In ) :: foo
Class( Parent ), Intent( In ) :: bar
End Subroutine i_Child_Parent
Subroutine i_set( foo, data )
Import :: Parent
Class( Parent ), Intent( InOut ) :: foo
Integer , Intent( In ) :: data
End Subroutine i_set
End Interface
Contains
Subroutine f_Child_Parent( foo, bar )
Implicit None
Class( Child ), Intent( In ) :: foo
Class( Parent ), Intent( In ) :: bar
Call bar%f_c_p( foo )
End Subroutine f_Child_Parent
Subroutine f_Child_Child( foo, bar )
Implicit None
Class( Child ), Intent( In ) :: foo
Class( Child ), Intent( In ) :: bar
Write( *, * ) 'In child child foo%data = ', foo%data, ' bar%data = ', bar%data
End Subroutine f_Child_Child
Subroutine f_Child_set( foo, data )
Implicit None
Class( Child ), Intent( InOut ) :: foo
Integer , Intent( In ) :: data
foo%data = data
End Subroutine f_Child_set
End Module m
Program driver
Use m, Only : Parent, Child
Class( Parent ), Allocatable :: foo, bar
Allocate( Child :: foo )
Allocate( Child :: bar )
Call foo%set( 3 )
Call bar%set( 4 )
Call foo%f( bar )
End Program driver
ian@eris:~/work/stack$ gfortran-8 -std=f2008 -fcheck=all -Wall -Wextra dd.f90
ian@eris:~/work/stack$ ./a.out
In child child foo%data = 3 bar%data = 4
ian@eris:~/work/stack$
这是否比
选择类型快取决于实现,但我认为它更干净。您可以使用单一分派两次:
Module m
Implicit None
Type, Public, Abstract :: Parent
Contains
Procedure( i_Parent_Parent ), Public , Deferred :: f
Procedure( i_Child_Parent ), Pass( bar ), Private, Deferred :: f_c_p
Procedure( i_set ), Public , Deferred :: set
End Type Parent
Type, Public, Extends( Parent ) :: Child
Integer , Private :: data
Contains
Procedure , Public :: f => f_Child_Parent
Procedure, Pass( bar ), Private :: f_c_p => f_Child_Child
Procedure , Public :: set => f_Child_set
End Type Child
Private
Abstract Interface
Subroutine i_Parent_Parent( foo, bar )
Import :: Parent
Implicit None
Class( Parent ), Intent( In ) :: foo
Class( Parent ), Intent( In ) :: bar
End Subroutine i_Parent_Parent
Subroutine i_Child_Parent( foo, bar )
Import :: Parent, Child
Implicit None
Class( Child ), Intent( In ) :: foo
Class( Parent ), Intent( In ) :: bar
End Subroutine i_Child_Parent
Subroutine i_set( foo, data )
Import :: Parent
Class( Parent ), Intent( InOut ) :: foo
Integer , Intent( In ) :: data
End Subroutine i_set
End Interface
Contains
Subroutine f_Child_Parent( foo, bar )
Implicit None
Class( Child ), Intent( In ) :: foo
Class( Parent ), Intent( In ) :: bar
Call bar%f_c_p( foo )
End Subroutine f_Child_Parent
Subroutine f_Child_Child( foo, bar )
Implicit None
Class( Child ), Intent( In ) :: foo
Class( Child ), Intent( In ) :: bar
Write( *, * ) 'In child child foo%data = ', foo%data, ' bar%data = ', bar%data
End Subroutine f_Child_Child
Subroutine f_Child_set( foo, data )
Implicit None
Class( Child ), Intent( InOut ) :: foo
Integer , Intent( In ) :: data
foo%data = data
End Subroutine f_Child_set
End Module m
Program driver
Use m, Only : Parent, Child
Class( Parent ), Allocatable :: foo, bar
Allocate( Child :: foo )
Allocate( Child :: bar )
Call foo%set( 3 )
Call bar%set( 4 )
Call foo%f( bar )
End Program driver
ian@eris:~/work/stack$ gfortran-8 -std=f2008 -fcheck=all -Wall -Wextra dd.f90
ian@eris:~/work/stack$ ./a.out
In child child foo%data = 3 bar%data = 4
ian@eris:~/work/stack$
这是否比select type
快取决于实现,但我认为它更干净。这很好地回答了问题,谢谢,但不幸的是在我的情况下不起作用。如果我让父模块依赖于不同的子模块,那么我就有循环依赖。看看你是否能提出一个更接近你需要的新问题(不要编辑这个问题),然后这里的人可以想一想,这很好地回答了所问的问题,谢谢,但不幸的是,在我的情况下不起作用。如果我让父模块依赖于不同的子模块,那么我就有循环依赖。看看你是否能提出一个更接近你需要的新问题(不要编辑这个问题),然后这里的人可以考虑一下,一般来说,性能和OOP是相互垂直的。因此,作为一般的经验法则,您应该避免在代码的性能关键部分使用OOP。这不是Fortran独有的,也适用于任何语言。一般来说,性能和OOP是相互垂直的。因此,作为一般的经验法则,您应该避免在代码的性能关键部分使用OOP。这不是Fortran独有的,适用于任何语言。