通过使用继承规则访问扩展主派生类型的派生类型的组件

时间:2018-06-26 07:31:38

标签: fortran gfortran

关于使用继承规则,我需要一些帮助。我的意图是使用一个派生类型数组存储计算结果,但我也想使用该数组存储主派生类型和扩展派生类型的组件值。 例如,这是我要转换的示例代码:

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 

在这种情况下,我无法使用指针P_INH和函数来获取不是扩展派生类型成员的组件I_BB值,因为我收到了以下编译错误消息:

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

在这种情况下哪种更改有用?

我的IDE是使用Gfortran编译器的Code :: Blocks 17.12。编译器的版本是:MinGW 6.3.0。

1 个答案:

答案 0 :(得分:2)

从根本上讲,所需的结果是调用与基本和派生类型关联的calculate例程,并访问与基本和派生类型关联的take例程。这必须通过派生类型来完成,因为基础对扩展它的类型一无所知。一种无需修改您的类型即可实现的方法是:

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

上面的输出是:

       2           3
       3           5
       4           7

应该选择calculate调用的顺序以匹配您的用例。

编辑: 为了扩展我的评论,如果您将calc_data_i_bb的定义修改为:

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

然后您可以简化驱动程序循环:

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

根据使用情况,这可能是一个更好的选择。