我试图使用接口来调用不同类型的不同子程序,但是,当我使用指针属性时,它似乎不起作用。例如,采用此示例代码
MODULE ptr_types
TYPE, abstract :: parent
INTEGER :: q
END TYPE
TYPE, extends(parent) :: child
INTEGER :: m
END TYPE
INTERFACE ptr_interface
MODULE PROCEDURE do_something
END INTERFACE
CONTAINS
SUBROUTINE do_something(atype)
CLASS(parent), POINTER :: atype
! code determines that this allocation is correct from input
ALLOCATE(child::atype)
WRITE (*,*) atype%q
END SUBROUTINE
END MODULE
PROGRAM testpass
USE ptr_types
CLASS(child), POINTER :: ctype
CALL ptr_interface(ctype)
END PROGRAM
这会给出错误 错误:(1)
处的通用'ptr_interface'没有特定的子程序但是,如果我删除子程序中的指针属性,它编译得很好。现在,通常这不会是一个问题,但对于我的用例,我需要能够将该参数视为指针,主要是因为我可以在必要时分配它。
有什么建议吗?请注意,我是Fortran的新手,所以我可能错过了一些东西
编辑:忘了把分配放在parent子程序中,初始输入是未分配的
编辑2 这是我的第二次尝试,通过调用方投射
MODULE ptr_types
TYPE, abstract :: parent
INTEGER :: q
END TYPE
TYPE, extends(parent) :: child
INTEGER :: m
END TYPE
TYPE, extends(parent) :: second
INTEGER :: meow
END TYPE
CONTAINS
SUBROUTINE do_something(this, type_num)
CLASS(parent), POINTER :: this
INTEGER type_num
IF (type_num == 0) THEN
ALLOCATE (child::this)
ELSE IF (type_num == 1) THEN
ALLOCATE (second::this)
ENDIF
END SUBROUTINE
END MODULE
PROGRAM testpass
USE ptr_types
CLASS(child), POINTER :: ctype
SELECT TYPE(ctype)
CLASS is (parent)
CALL do_something(ctype, 0)
END SELECT
WRITE (*,*) ctype%q
END PROGRAM
然而,这仍然失败。在select语句中,它抱怨父级必须扩展子级。我确定这是由于处理指针属性时的限制,对于类型安全,但是,我正在寻找一种方法将指针转换为其父类型以进行通用分配。而不是必须为每种类型编写单独的分配函数,并希望它们不会在界面或其他东西中发生碰撞。
希望这个例子能够更清楚地说明我想要实现的目标,如果你知道更好的方式让我知道
答案 0 :(得分:2)
如高性能标记所示,您对ptr_interface
调用的实际参数和伪参数的声明类型不匹配。如果伪参数具有指针或可分配属性,则不允许这样做 - 参见F2008的12.5.2.5p2。
这种限制有一个简单的基本原理(在F2008标准的注释12.27中讨论过) - 没有它,子程序就可以将伪参数分配为与实际参数不兼容的类型。例如 - 想象一下程序中是否存在Parent
的另一个扩展名 - 类型为heirarchy的Child
的兄弟。如果您的do_something
过程将其伪参数分配给该兄弟类型,那么返回调用范围,您将声明为类型Child
的东西实际上是其他不兼容的(不是Child的扩展)类型。
如果do_something过程无法将事物分配给除类型Child之外的任何内容,则使其伪类型为Child。如果它可以将它分配给作为Parent的扩展的其他类型,那么您还需要将实际参数类型的声明类型设置为Parent。您可以使用SELECT TYPE构造然后向下转换为调用范围中的Child类型的对象。
在您编辑之后,我的建议是让您的主程序看起来像:
PROGRAM testpass
USE ptr_types
IMPLICIT NONE ! <--
CLASS(Parent), POINTER :: ctype
!***
! ctype here is a pointer with undefined association status,
! (so no concept of dynamic type) and declared type Parent.
CALL do_something(ctype, 0)
! Assuming successful ALLOCATE(Child :: xxx) in the procedure,
! ctype here is an associated pointer with dynamic type Child.
SELECT TYPE(ctype)
CLASS is (Child)
! Declared type of ctype in here is Child. Dynamic type
! in this specific case is also Child, but this block would
! also be executed if the dynamic type was a further extension
! of Child, because a CLASS IS guard was used. (A TYPE IS
! guard requires an exact match of dynamic type.)
!
! If the allocate in do_something allocated the dummy argument
! to be of type second or nullified the argument, then this
! block of code would not be executed. If do_something left
! the association status of the pointer undefined, then
! your program is non-conforming, and anything could happen.
WRITE (*,*) ctype%m
! Continue to work with ctype as a thing with declared type
! Child inside this block of the select type construct.
END SELECT
! ctype back to having a declared type of Parent.
WRITE (*,*) ctype%q
! Don't forget deallocation!
END PROGRAM
答案 1 :(得分:0)
如果我改变你的行
CLASS(child), POINTER :: ctype
到
CLASS(parent), POINTER :: ctype
然后你的程序编译并执行。我对所有这个面向对象的Fortran都很陌生,所以我很难指出标准中的条款,该条款规定了在这种情况下排序类型匹配的规则并澄清了你的错误。您的错误可能只是使用不实现该语言最新功能的编译器。另一方面,也许我的编译器(英特尔Fortran 13.1)实现的最新功能与您的不同。
(在过去的形式上,一个名叫IanH的人在SO上将会过去并澄清。)
我学到的一件事是,如果您的编译器符合Fortran 2003(足够),那么创建变量ALLOCATABLE
而不是POINTER
会使一些操作变得更容易,并且负责释放不需要的内容内存到编译器。您不再需要Fortran中的动态内存管理指针。
答案 2 :(得分:0)
我认为您的问题来自子例程do_something中参数的POINTER属性。删除它,一切都应该有效。