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.