在2003年的Fortran上升/下行?

Ste*_*ini 3 oop fortran

在Fortran 2003中,标准中定义了类和OOP.我想知道如何进行上升和下行.

Wil*_*cat 7

实际上你可以使用这种方法开箱即用(但不是向下投射)开箱即用:

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
Run Code Online (Sandbox Code Playgroud)

注意:

  • 你想要向上转换的类型变量应该是多态的(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
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您不需要使用多态实体和特殊形式的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
Run Code Online (Sandbox Code Playgroud)

沮丧...嗯...这是不安全的,它违背了强大的打字纪律.当我面对挫折时,我试图以相同的方式思考 - 使用相同的方法.您需要定义另一个任务 - 从父级到子级.唯一的问题是如果你将使用完全相同的方案(GENERIC绑定),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
Run Code Online (Sandbox Code Playgroud)

但这不是一个降级.向下转换是将对基类的引用转换为其派生类之一.您需要检查引用对象的类型是否确实是要转换的对象的类型或它的派生类型,因此如果不是这样,则发出错误.

星期五晚上...做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
Run Code Online (Sandbox Code Playgroud)

  • 我的印象是,在Fortran规范的每一次新迭代中,语言越来越接近爆炸.谢谢你所有的好东西. (4认同)