【问题标题】:up/downcasting in fortran 2003?在fortran 2003中向上/向下转换?
【发布时间】:2011-01-20 11:07:13
【问题描述】:

在 fortran 2003 中,标准中定义了类和 OOP。我想知道如何执行向上转换和向下转换。

【问题讨论】:

    标签: oop fortran


    【解决方案1】:

    实际上,您可以使用这种方法进行开箱即用的向上转换(但不能向下转换):

    PROGRAM main
    
      IMPLICIT NONE
    
      TYPE :: parent
        INTEGER :: a
      END TYPE parent
    
      TYPE, EXTENDS(parent) :: child
        INTEGER :: b
      END TYPE child
    
      CLASS(parent), ALLOCATABLE :: p
      TYPE(child) :: c
    
      ALLOCATE (p)
    
      p%a = 5
      c%a = 10
      c%b = 15
    
      PRINT *, p%a
    
      ! p = c
      DEALLOCATE (p)
      ALLOCATE (p, source=c)
    
      PRINT *, p%a
    
      DEALLOCATE (p)
    
    END PROGRAM main
    

    注意:

    • 要向上转换的类型变量应该是多态的(CLASS 而不是 TYPE);
    • 您不能对多态变量使用内在赋值(ALLOCATE 而不是 =)。
    • 英特尔编译器可能仍不支持带有 source= 子句的 ALLOCATE。

    或者您可以定义从子类型到父类型的分配:

    MODULE types
    
      IMPLICIT NONE
    
      TYPE :: parent
        INTEGER :: a
      CONTAINS
        PROCEDURE, PRIVATE :: parent_from_child
        GENERIC :: ASSIGNMENT(=) => parent_from_child
      END TYPE parent
    
      TYPE, EXTENDS(parent) :: child
        INTEGER :: b
      END TYPE child
    
      CONTAINS
    
        SUBROUTINE parent_from_child(this, c)
          CLASS(parent), INTENT(INOUT) :: this
          CLASS(child), INTENT(IN) :: c
    
          this%a = c%a
        END SUBROUTINE parent_from_child
    
    END MODULE types
    

    在这种情况下,您不需要使用多态实体和特殊形式的 ALLOCATABLE 语句:

    PROGRAM main
    
      USE types
    
      IMPLICIT NONE
    
      TYPE(parent) :: p
      TYPE(child) :: c
    
      p%a = 5
      c%a = 10
      c%b = 15
    
      PRINT *, p%a
    
      p = c
    
      PRINT *, p%a
    
    END PROGRAM main
    

    向下转换...嗯...这是不安全的,它违反了严格的打字纪律。当我面临沮丧时,我很想以同样的方式思考——使用同样的方法。您只需要定义另一个分配 - 从父母到孩子。唯一的问题是,如果您将使用完全相同的方案(通用绑定)child_from_parent 将无法与 parent_from_child 区分开来。但是,您可以通过其他方式做到这一点:

    MODULE types
    
      IMPLICIT NONE
    
      INTERFACE ASSIGNMENT(=)
        MODULE PROCEDURE parent_from_child, child_from_parent
      END INTERFACE
    
      TYPE :: parent
        INTEGER :: a
      END TYPE parent
    
      TYPE, EXTENDS(parent) :: child
        INTEGER :: b
      END TYPE child
    
      CONTAINS
    
        SUBROUTINE parent_from_child(this, c)
          TYPE(parent), INTENT(INOUT) :: this
          CLASS(child), INTENT(IN) :: c
    
          this%a = c%a
        END SUBROUTINE parent_from_child
    
        SUBROUTINE child_from_parent(this, p)
          TYPE(child), INTENT(INOUT) :: this
          CLASS(parent), INTENT(IN) :: p
    
          this%a = p%a
          this%b = 0
        END SUBROUTINE child_from_parent
    
    END MODULE types
    
    PROGRAM main
    
      USE types
    
      IMPLICIT NONE
    
      CLASS(parent), ALLOCATABLE :: p
      TYPE(child) :: c
    
      c%a = 10
      c%b = 15
    
      ALLOCATE (p, source=c)
    
      c%a = 5
      PRINT *, c%a
    
      c = p
      PRINT *, c%a
    
    END PROGRAM main
    

    但这不是向下转换。向下转换是将基类的引用转换为其派生类之一。您需要检查被引用对象的类型是否确实是被强制转换的类型或它的派生类型,如果不是,则发出错误。

    星期五晚上... 做一些 Fortran 的好时机。 =) 最后我得到了:

    MODULE types
    
      IMPLICIT NONE
    
      TYPE :: parent
        INTEGER :: a
      END TYPE parent
    
      TYPE, EXTENDS(parent) :: child
        INTEGER :: b
      END TYPE child
    
      CONTAINS
    
        SUBROUTINE cast(from, to)
          CLASS(parent), INTENT(IN) :: from
          CLASS(parent), INTENT(INOUT) :: to
    
          SELECT TYPE (to)
            TYPE IS (parent)
              SELECT TYPE (from)
                TYPE IS (parent)
                  PRINT *, "ordinary assignment"
                  to = from
                TYPE IS (child)
                  PRINT *, "up-casting"
                  to%a = from%a
              END SELECT
            TYPE IS (child)
              SELECT TYPE (from)
                TYPE IS (parent)
                  PRINT *, "No way!"
                TYPE IS (child)
                  PRINT *, "down-casting"
                  to = from
              END SELECT
          END SELECT
        END SUBROUTINE cast
    
    END MODULE types
    
    PROGRAM main
    
      USE types
    
      IMPLICIT NONE
    
      CLASS(parent), ALLOCATABLE :: p1, p2
      TYPE(child) :: c1, c2
    
      ALLOCATE (p1, p2)
    
      p1%a = 1
      p2%a = 2
      c1%a = 1
      c1%b = 1
      c2%a = 2
      c2%b = 2
    
      PRINT *, p1%a
      ! up-casting from c2 to p1
      CALL cast(c2, p1)
      PRINT *, p1%a
    
      PRINT *, "----------"
    
      DEALLOCATE (p2)
      ALLOCATE (p2, source=c1)
    
      PRINT *, c2%a, c2%b
      ! down-casting from p2 to c2
      CALL cast(p2, c2)
      PRINT *, c2%a, c2%b
    
      DEALLOCATE (p1, p2)
    
    END PROGRAM main
    

    【讨论】:

    • 我的印象是,在 Fortran 规范的每一次新迭代中,该语言都越来越接近崩溃。谢谢你所有的好东西。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多