Fortran多态性的指针 [英] Fortran polymorphism in pointers
问题描述
我想使用指针来创建对象之间的链接。使用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多态性的指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!