Enlil Maratovich
Enlil Maratovich

Reputation: 59

Accessing to components of derived types which extends main derived type by using inheritance rule

I need a little help about using inheritance rules. My intention is to use one derived type array for storaging results of calculation but i want to use that array also for storaging components values from main and extended derived types. For example, this is my example code which I want to transform:

MODULE DERIVED_TYPES

IMPLICIT NONE

! FIRST DERIVED TYPE

TYPE, PUBLIC :: DT_AA

  INTEGER, PRIVATE :: I_AA

  CONTAINS

  PROCEDURE, PUBLIC:: CALCULATE => CALC_DATA_I_AA
  PROCEDURE, PUBLIC::    T_I_AA => TAKE_DATA_I_AA

END TYPE DT_AA

PRIVATE :: CALC_DATA_I_AA
PRIVATE :: TAKE_DATA_I_AA

! SECOND DERIVED TYPE

TYPE, EXTENDS( DT_AA ), PUBLIC :: DT_BB

  INTEGER, PRIVATE :: I_BB

  CONTAINS

  PROCEDURE, PUBLIC:: CALCULATE => CALC_DATA_I_BB
  PROCEDURE, PUBLIC::    T_I_BB => TAKE_DATA_I_BB

END TYPE DT_BB

PRIVATE :: CALC_DATA_I_BB
PRIVATE :: TAKE_DATA_I_BB

CONTAINS

! TYPE DT_AA PROCEDURES

  SUBROUTINE CALC_DATA_I_AA( THIS, INDX )

    CLASS( DT_AA ) :: THIS
    INTEGER, INTENT( IN ) :: INDX

    THIS%I_AA = 1 + INDX

  END SUBROUTINE CALC_DATA_I_AA

  FUNCTION TAKE_DATA_I_AA( THIS ) RESULT( VALUE_I_AA )

    CLASS( DT_AA ) THIS
    INTEGER :: VALUE_I_AA

    VALUE_I_AA = THIS%I_AA

  END FUNCTION TAKE_DATA_I_AA

! TYPE DT_BB PROCEDURES

  SUBROUTINE CALC_DATA_I_BB( THIS, INDX )

    CLASS( DT_BB ) :: THIS
    INTEGER, INTENT( IN ) :: INDX

    THIS%I_BB = THIS%I_AA + INDX

  END SUBROUTINE CALC_DATA_I_BB

  FUNCTION TAKE_DATA_I_BB( THIS ) RESULT( VALUE_I_BB )

    CLASS( DT_BB ) THIS
    INTEGER :: VALUE_I_BB

    VALUE_I_BB = THIS%I_BB

  END FUNCTION TAKE_DATA_I_BB

END MODULE DERIVED_TYPES

PROGRAM INHERITANCE_RULE

USE, NON_INTRINSIC :: DERIVED_TYPES

IMPLICIT NONE

INTEGER :: I
INTEGER, PARAMETER :: N_CALC = 3

CLASS( DT_AA ), POINTER :: P_INH
 TYPE( DT_AA ),  TARGET :: P_A_INH( N_CALC )

DO I = 1, N_CALC

   P_INH => P_A_INH( I )

   CALL P_INH%CALCULATE( I )

   WRITE(*,*) P_INH%T_I_AA(), P_INH%T_I_BB()

END DO

END PROGRAM INHERITANCE_RULE 

In this case I can not use pointer P_INH and function for taking component I_BB values which is not member of extended derived type because I got this compile error message:

't_i_bb' is not a member of the 'dt_aa' structure

Which kind of change is useful for this case?

My IDE is Code::Blocks 17.12 with Gfortran compiler. The version of compiler is: MinGW 6.3.0.

Upvotes: 0

Views: 742

Answers (1)

ptb
ptb

Reputation: 2148

Fundamentally, the desired outcome is to call the calculate routines associated with the base and derived type and access the take routines associated with the base and derived type. This has to be done through the derived type as the base knows nothing about the types which extend it. One way to achieve this without modifying your types is:

type(dt_bb) :: b(n_calc)

do i = 1, n_calc

    call b(i)%dt_aa%calculate(i)
    call b(i)%calculate(i)

    write(*,*) b(i)%t_i_aa(), b(i)%t_i_bb()

end do

The output of the above is:

       2           3
       3           5
       4           7

The order of the calculate calls should be chosen to match your use case.

Edit: To expand on my comment, If you modify the definition of calc_data_i_bb to:

subroutine calc_data_i_bb( this, indx )

    class( dt_bb ) :: this
    integer, intent( in ) :: indx

    call this%dt_aa%calculate(indx)
    this%i_bb = this%i_aa + indx

end subroutine calc_data_i_bb

Then you can simplify the driver loop:

type(dt_bb) :: b(n_calc)

do i = 1, n_calc

    call b(i)%calculate(i)

    write(*,*) b(i)%t_i_aa(), b(i)%t_i_bb()

end do

This may be a better option depending on the use case.

Upvotes: 2

Related Questions