问题描述
我想使用指针来创建对象之间的链接。使用Fortran和这里是代码片:
模块base_pars_module
type,abstract,public :: base_pars
end type
结束模块
模块test_parameters_module
使用base_pars_module
类型,extends(base_pars):: test_pars
包含
procedure :: whoami
end type
包含
函数whoami(this)result(iostat)
class(test_pars):: this
write(*,*)' base_pars'
结束类型
结束模块
模块base_mask_module
使用base_pars模块
type,abstract,public :: base_mask
类(base_pars),指针: :parameters
end type
end module
module test_mask_module
use base_mask_module
implicit none
type,extends(base_mask):: test_mask
end类型
结束模块
程序驱动程序
类型(test_pars),target :: par_Test
类型(test_mask):: mask_test
iostat = par_test%whoami $ b mask_test%parameters => par_test
iostat = mask_test%parameters%whoami()
结束程序
参数在 base_mask_module 是一个指向 base_pars 类。我想使用这个指针引用 par_test 对象 test_pars 类型扩展 base_pars 类型。所以指针和目标具有相同的类。但是当我编译这个它给出一个错误:
driver.f90:17.37:
iostat = mask_test%parameters%whoami()
1
错误:'whoami'at(1)不是'base_pars'结构的成员
这是错误还是我做错了?
当你有这样的多态性时,有两个事情要考虑一个对象:它的动态类型和其声明类型。 test_mask ( base_mask )的参数组件声明为
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 构造。
code> select type(pars => mask_test%parameters)
class is(par_test)
iostat = pars%whoami与mask_test%参数关联的声明类型par_test的pars
end select
相当快地用这种方法相当乏味。总是使用 select type ,区分大量扩展类型,将是相当绑定。另一种方法是确保声明的类型 base_pars 有一个绑定 whoami 。不是像上面那样改变主程序,而是改变模块 base_pars_module :
module base_par_modules
implicit none!鼓励良好的做法
type,abstract,public :: base_pars
包含
过程(whoami_if),deferred :: whoami
结束类型
$ b b interface
integer function whoami_if(this)
import base_pars!回到我们在模块的不同范围
class(base_pars)this
end function
end interface
结束模块
因此,我们在 base_pars 中有一个延迟绑定通过扩展类型 test_pars 中的绑定。 mask_test%parameters%whoami()在主程序中是一个有效的函数,调用的函数是由动态类型参数$这两种方法都解决了参数的声明类型的绑定问题。
如果你知道你的类型层次结构与基本类型有足够的共同点,那就是,所有将提供 whoami 绑定),那么它是有意义的去第二种方法。使用第一种方法,而不是当你有奇怪的特殊情况,我建议应该是罕见的。
I am trying to use pointers to create links between objects. Using Fortran and here is the code piece:
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 is a pointer with base_pars class. I would like to use this pointer to refer par_test object which is test_pars type that extends base_pars type. So the pointer and the target has the same class. But when I compile this it gives an error:
driver.f90:17.37: iostat=mask_test%parameters%whoami() 1 Error: 'whoami' at (1) is not a member of the 'base_pars' structure
Is it a bug or am i doing something wrong?
When you have polymorphism like this there are two things to consider about an object: its dynamic type and its declared type. The parameters component of test_mask (base_mask) is declared as
class(base_pars),pointer :: parameters
Such a component therefore has declared type base_pars.
Come the pointer assignment
mask_test%parameters=>par_test
mask_test%parameters has dynamic type the same as par_test: test_pars. It's of declared type base_pars, though, and it's the declared type that is important when we care about its components and bindings. base_pars indeed has no whoami.
You need, then, something which has declared type par_test. Without changing the definitions of the derived types you can do this with the select type construct.
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
That said, things get pretty tedious quite quickly with this approach. Always using select type, distinguishing between numerous extending types, will be quite a bind. An alternative would be to ensure that the declared type base_pars has a binding whoami. Instead of changing the main program as above, we alter the module 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
So, we've a deferred binding in base_pars that is later over-ridden by a binding in the extending type test_pars. mask_test%parameters%whoami() in the main program is then a valid and the function called is that offered by the dynamic type of parameters.
Both approaches here address the problem with the binding of the declared type of parameters. Which best suits your real-world problem depends on your overall design.
If you know that your hierarchy of types will all have enough in common with the base type (that is, all will offer a whoami binding) then it makes sense to go for this second approach. Use the first approach rather when you have odd special cases, which I'd suggest should be rare.
这篇关于Fortran多态性的指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!