Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/sharepoint/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
我可以在Fortran中模拟多个传递的对象伪参数吗?_Fortran_Polymorphism - Fatal编程技术网

我可以在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独有的,适用于任何语言。