【发布时间】:2011-01-20 11:07:13
【问题描述】:
在 fortran 2003 中,标准中定义了类和 OOP。我想知道如何执行向上转换和向下转换。
【问题讨论】:
在 fortran 2003 中,标准中定义了类和 OOP。我想知道如何执行向上转换和向下转换。
【问题讨论】:
实际上,您可以使用这种方法进行开箱即用的向上转换(但不能向下转换):
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
注意:
或者您可以定义从子类型到父类型的分配:
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
【讨论】: