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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With