【问题标题】:Fortran polymorphism in pointers指针中的 Fortran 多态性
【发布时间】:2015-09-22 03:08:29
【问题描述】:

我正在尝试使用指针来创建对象之间的链接。使用 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

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

 driver.f90:17.37:

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

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

【问题讨论】:

  • 此代码无法编译。您在主程序中缺少一些 uses。

标签: class pointers fortran polymorphism


【解决方案1】:

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

class(base_pars),pointer :: parameters

因此,此类组件已声明类型 base_pars。

来指针赋值

mask_test%parameters=>par_test

mask_test%parameters 具有与par_test 相同的动态类型:test_pars。不过,它是声明类型base_pars,当我们关心它的组件和绑定时,它是重要的声明类型。 base_pars确实没有whoami。

那么,您需要声明类型为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

也就是说,使用这种方法,事情很快就会变得非常乏味。总是使用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

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

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

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

【讨论】:

  • 作为一个松散的准则(存在有效的例外),选择类型的使用是底层类型层次结构问题的征兆,特别是如果所有代码都在调用选择器的绑定(其中如果您通过选择类型进行动态调度以通过绑定调用动态调度)。这完全取决于 OP 试图做什么,但更合适的解决方案可能是将 whoami 绑定作为延迟绑定移动到基本类型中。在此答案中使用 select type 至少应附加某种限定条件。
  • 谢谢。我希望涵盖你的评论。回想起来,我最初确实应该考虑更笼统的观点。
  • 感谢@francescalus 的解释,但延迟绑定不是这里的解决方案。我试图做的是在同一类的对象之间建立连接。函数“whoami”只是一个例子。我希望所有继承“base_mask”对象的对象都有一个类“base_pars”的指针。
  • @dundaryilmaz 恐怕我可能误解了你的问题,但是当你有一个声明类型为 base_pars 的组件指针时(如问题所示),那么你不能引用绑定不在base_pars 声明中的组件。无论其动态类型如何。如果您希望test_mask 的组件具有声明类型test_pars(例如),那么您必须将其声明为这样,而不是依赖于test_pars 的动态类型。 (除非您使用 select type 构造。)
  • @francescalus 好吧,我尝试将其与类概念一样。由于 base_pars 和 test_pars 具有父子关系,因此声明的具有父类/类型的指针应该与子类/类型一起使用。我相信其他 OO 语言也是这样工作的。
猜你喜欢
  • 1970-01-01
  • 2019-04-24
  • 1970-01-01
  • 2013-05-10
  • 1970-01-01
  • 1970-01-01
  • 2018-11-15
  • 2021-07-06
  • 1970-01-01
相关资源
最近更新 更多