问题
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?
回答1:
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.
来源:https://stackoverflow.com/questions/31220961/fortran-polymorphism-in-pointers