Class 指针中的Fortran多态性

Class 指针中的Fortran多态性,class,pointers,fortran,polymorphism,Class,Pointers,Fortran,Polymorphism,我尝试使用指针在对象之间创建链接。使用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 :: w

我尝试使用指针在对象之间创建链接。使用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
base\u mask\u模块处的
parameters
是带有
base\u pars
类的指针。我想用这个指针来引用
par\u test
对象,它是扩展
base\u pars
类型的
test\u pars
类型。因此指针和目标具有相同的类。但当我编译这个时,它会给出一个错误:

 driver.f90:17.37:

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

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

当你有这样的多态性时,有两件事需要考虑:一个对象的动态类型和它的声明类型。
测试掩码
基本掩码
)的
参数
组件声明为

class(base_pars),pointer :: parameters
因此,这样的组件已声明类型
base\u pars

接下来是指针分配

mask_test%parameters=>par_test
mask\u test%参数的动态类型与
par\u test
相同:
test\u pars
。但是,它是声明的类型
base\u pars
,当我们关心它的组件和绑定时,声明的类型很重要
base\u pars
确实没有
whoami

那么,您需要一个声明了type
par\u 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
也就是说,使用这种方法很快就会变得非常乏味。始终使用
选择类型
,区分众多扩展类型,将是一个相当大的难题。另一种方法是确保声明的类型
base\u pars
具有绑定
whoami
。我们没有如上所述更改主程序,而是更改模块
base\u pars\u 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
因此,我们在
base\u pars
中有一个延迟绑定,该绑定后来被扩展类型
test\u pars
中的绑定覆盖<然后,主程序中的code>mask\u test%parameters%whoami()
是有效的,调用的函数是动态类型的
parameters
提供的函数

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


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

但是,这段代码无法编译。主程序中缺少一些
use
s。作为松散的指导原则(存在有效的异常),使用select type是基础类型层次结构出现问题的征兆,特别是当代码所做的一切都是调用选择器的绑定时(在这种情况下,您可以通过选择类型进行动态分派,以通过绑定调用动态分派)。这完全取决于OP试图做什么,但更合适的解决方案可能是将
whoami
绑定作为延迟绑定移动到基类型中。在这个回答中,至少应该对选择类型的使用附加某种限定。谢谢。我希望已经涵盖了您的评论。经过反思,我应该ed一开始就谈到了更一般的问题。感谢@francescalus的解释,但延迟绑定在这里不是一个解决方案。我试图做的是在同一类的对象之间建立连接。函数“whoami”只是一个例子。我希望所有继承“base_mask”对象的对象都有一个类“b”的指针ase_pars.@dundaryilmaz恐怕我可能误解了您的问题,但是当您有一个声明类型为
base_pars
的组件指针时(如问题中所述),则不能引用不在
基本部分声明中的组件的绑定,无论其动态类型如何。如果希望
测试部分声明类型
测试部分
(例如)然后您必须声明它是这样的,而不是依赖于动态类型
test\u pars
(除非您使用
select type
构造)@francescalus我试着用类的概念来做这件事。因为base_pars和test_pars有父子关系,父类/类型的声明指针应该和子类/类型一起工作。我相信其他OO语言也是这样工作的。