I have a number of types declared which extend a base type with their own functionality. I came to notice that many of them had similar data structure so I decided to incorporate this data structure into the base class. The declarations might be the following:
TYPE Base REAL, PRIVATE :: Apple = 0.0 REAL, PRIVATE :: Banana = 1.0 CONTAINS PROCEDURE :: Get_Apple PROCEDURE :: Get_Banana PROCEDURE :: Set_Apple PROCEDURE :: Set_Banana END TYPE Base REAL FUNCTION Get_Apple(this) CLASS (Base), INTENT(IN) :: this Get_Apple = this%Apple END FUNCTION Get_Apple ! Similar FUNCTION for Get_Banana SUBROUTINE Set_Apple(this, vAppleValue) CLASS (Base), INTENT(INOUT) :: this REAL, INTENT(IN) :: vAppleValue this%Apple = vAppleValue END SUBROUTINE Set_Apple ! Similar SUBROUTINE for Set_Banana
Now in the extended types, access to Apple and Banana are available with the procedures. The question is, outside of the extended types, how might I "Get_Apple" or "Get_Banana". That is, if I have an instance of
TYPE, EXTENDS(Base) :: Fruit REAL, PRIVATE :: Mango REAL, PRIVATE :: Kiwi CONTAINS PROCEDURE :: Get_Huh END TYPE Fruit
how might I get Apple or Banana? Simple calls to Get_Apple or Get_Banana do not suffice despite the fact I can use them "internally" within procedures in Fruit.
Assuming you have:
Type(Fruit) :: Durian
you can do:
something = Durian%GetApple()
When you extend a type, the type inherits all of the accessible components and type-bound procedures of the parent. In the example you posted, while the components Apple and Banana are private, the TBPs are not. This is in fact the desirable way of organizing things.
Or am I not understanding your question?
Thank you, Dr. Fortran Emeritus. That was precisely what I was doing, but failing. Per usual, there was something behind the scenes causing grief. Let me explain. The declaration of TYPE Fruit was encased in a module as follows:
MODULE Fruit_Module USE Base_Module, ONLY : Base TYPE, EXTENDS(Base) :: Fruit ! Blah, blah, blah END MODULE Fruit_Module
But the declaration of Fruit in the external routine was something along the lines of
SUBROUTINE Cultivate(Orchard) USE Fruit_Module, ONLY : Fruit TYPE (Fruit), POINTER :: Orchard REAL Pome ! This will not compile because Fruit has no access to Get_Apple! Pome = Orchard%Get_Apple() END SUBROUTINE Cultivate
What needs to happen is
SUBROUTINE Cultivate(Orchard) USE Base_Module, ONLY : Base USE Fruit_Module, ONLY : Fruit TYPE (Fruit), POINTER :: Orchard REAL Pome ! This will compile because Fruit%Base has access to Get_Apple! Pome = Orchard%Get_Apple() END SUBROUTINE Cultivate
Once again, thank you for the reassurance that my construction was correct. It was the underpinnings which were lacking.
Now I am having some more trouble with my Base class and its use with Fruit of many types. I wrote an external routine which applied to Fruit only. I then needed to use that routine for Durian without changing anything within the routine. In essence the routine is a carbon copy, only with Durian replacing Fruit.
The idea I thought would be to put the routine within Base with the argument in question now declared as CLASS (Base). Then the routine would be accessed from the Fruit class or the Durian class being as CLASS (Base) is polymorphic.
Unfortunately, there is an internal CALL within the routine to another CLASS which is now not compiling. The complaint is the "this" argument type differs from the type of the dummy argument. The "this" argument is declared as
CLASS (Base), INTENT(INOUT) :: this
Within the called routine in the other CLASS it is declared as
CLASS (Base), TARGET, INTENT(INOUT) :: Tomato
No matter how I swing it, I cannot get the two arguments to sync. I am always getting error #6633.
I have a fix for the problem I quoted. The fix is to make the routine an external routine.
SUBROUTINE HandleFruit(FB, A, B) USE Base_Module, ONLY : Base CLASS (Base), INTENT(INOUT) :: FB REAL, INTENT(INOUT) :: A REAL, INTENT(INOUT) :: B TYPE (OtherClass) :: OC CALL OC%SolutionMethod(A, B, FB) END SUBROUTINE HandleFruit
With the Base class polymorphic, I can call this routine for any FB argument which extends Base. This is precisely what I need to do. I am unsure why I would have wanted routine HandleFruit in the Base class. It should be an external routine.