Fortran指针作为接口过程的参数

时间:2013-06-26 08:52:45

标签: pointers fortran

我试图使用接口来调用不同类型的不同子程序,但是,当我使用指针属性时,它似乎不起作用。例如,采用此示例代码

 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语句中,它抱怨父级必须扩展子级。我确定这是由于处理指针属性时的限制,对于类型安全,但是,我正在寻找一种方法将指针转换为其父类型以进行通用分配。而不是必须为每种类型编写单独的分配函数,并希望它们不会在界面或其他东西中发生碰撞。

希望这个例子能够更清楚地说明我想要实现的目标,如果你知道更好的方式让我知道

3 个答案:

答案 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属性。删除它,一切都应该有效。