指针中的 Fortran 多态性

dun*_*maz 3 polymorphism fortran pointers class

我正在尝试使用指针在对象之间创建链接。使用 Fortran,这里是代码段:

 module base_pars_module
   type,abstract,public :: base_pars
   end type
 end module 
 module test_parameters_module
   use base_pars_module
   type, extends(base_pars) :: test_pars
     contains 
     procedure :: whoami
   end type
   contains
   function whoami(this) result(iostat)
     class( test_pars) :: this
     write(*,*) 'i am a derived type child of base_pars'
   end type
 end module
 module base_mask_module
   use base_pars module
     type, abstract , public :: base_mask
     class(base_pars),pointer :: parameters
   end type
end module
module test_mask_module
  use base_mask_module
  implicit none
  type, extends(base_mask) :: test_mask
  end type
end module
program driver
type(test_pars) , target :: par_Test
type(test_mask) :: mask_test
  iostat= par_test%whoami()
  mask_test%parameters=>par_test
  iostat=mask_test%parameters%whoami()
end program
Run Code Online (Sandbox Code Playgroud)

parametersatbase_mask_module是一个带base_pars类的指针。我想使用这个指针来引用扩展类型的par_test对象。所以指针和目标具有相同的类。但是当我编译它时,它给出了一个错误:test_parsbase_pars

 driver.f90:17.37:

iostat=mask_test%parameters%whoami()
                                  1
Error: 'whoami' at (1) is not a member of the 'base_pars' structure
Run Code Online (Sandbox Code Playgroud)

这是一个错误还是我做错了什么?

fra*_*lus 6

当你有这样的多态性时,关于一个对象需要考虑两件事:它的动态类型和它的声明类型。( )的parameters组成部分声明为test_maskbase_mask

class(base_pars),pointer :: parameters
Run Code Online (Sandbox Code Playgroud)

因此,此类组件已声明 type base_pars

来个指针赋值

mask_test%parameters=>par_test
Run Code Online (Sandbox Code Playgroud)

mask_test%parameters具有与par_test:相同的动态类型test_pars。这是声明的类型的base_pars,虽然,这是声明的类型时,我们在意它的组件和绑定是非常重要的。 base_pars确实没有whoami

那么,您需要声明 type 的东西par_test。在不更改派生类型的定义的情况下,您可以使用select type构造来执行此操作。

select type (pars => mask_test%parameters)
class is (par_test)
  iostat=pars%whoami()  ! pars of declared type par_test associated with mask_test%parameters
end select
Run Code Online (Sandbox Code Playgroud)

也就是说,使用这种方法很快就会变得非常乏味。总是使用select type,区分众多扩展类型,将是一个很大的束缚。另一种方法是确保声明的类型base_pars具有绑定whoami。我们没有像上面那样更改主程序,而是更改模块base_pars_module

module base_par_modules
  implicit none  ! Encourage good practice

  type,abstract,public :: base_pars
   contains
    procedure(whoami_if), deferred :: whoami
  end type

  interface
    integer function whoami_if(this)
      import base_pars    ! Recall we're in a different scope from the module
      class(base_pars) this
    end function
  end interface

end module
Run Code Online (Sandbox Code Playgroud)

所以,我们有一个延迟绑定base_pars,后来被扩展类型中的绑定覆盖test_parsmask_test%parameters%whoami()在主程序中是一个有效的,被调用的函数是由动态类型提供的parameters

这里的两种方法都解决了声明类型的绑定问题parameters。哪种最适合您的实际问题取决于您的整体设计。

如果您知道您的类型层次结构都与基本类型有足够的共同点(即,所有类型都将提供whoami绑定),那么采用第二种方法是有意义的。当您遇到奇怪的特殊情况时,请使用第一种方法,我建议这种情况很少见。