如何覆盖fortran中的结构构造函数

时间:2010-11-23 23:52:32

标签: constructor fortran gfortran user-defined-types

目前是否可以覆盖Fortran中的结构构造函数?我已经看到了这样的提议示例(例如在Fortran 2003规范中):

module mymod

  type mytype
    integer :: x
    ! Other stuff
  end type

  interface mytype
    module procedure init_mytype
  end interface

contains
  type(mytype) function init_mytype(i)
    integer, intent(in) :: i
    if(i > 0) then
      init_mytype%x = 1
    else
      init_mytype%x = 2
    end if
  end function
end

program test
  use mymod
  type(mytype) :: x
  x = mytype(0)
end program

由于冗余变量名称(例如,'mytype'的错误:DERIVED属性与(1)处的PROCEDURE属性冲突),这基本上会产生一堆错误。 fortran 2003示例的逐字副本会产生类似的错误。我在gfortran 4.4,ifort 10.1和11.1中尝试了这个,它们都产生了相同的错误。

我的问题:这只是2003年fortran的一个未实现的功能吗?或者我是否错误地实施了这个?

编辑:我遇到过关于此问题的bug reportannounced patch gfortran。但是,我尝试使用11月版的gcc46没有运气和类似的错误。

编辑2:上述代码似乎可以使用英特尔Fortran 12.1.0。

2 个答案:

答案 0 :(得分:18)

  

目前是否可以覆盖Fortran中的结构构造函数?

不。无论如何,即使使用您的方法也完全不是构造函数重写。主要原因是结构构造函数#OOP构造函数。有一些相似之处,但这只是另一个想法。

您不能在初始化表达式中使用非内在函数。您可以只使用常量,数组或结构构造函数,内部函数,...有关更多信息,请参阅Fortran 2003草案中的7.1.7初始化表达式。

考虑到这一事实,我完全不明白

之间的真正区别
type(mytype) :: x
x = mytype(0)

type(mytype) :: x
x = init_mytype(0)

在mymod MODULE中使用INTERFACE块的重点是什么。

嗯,老实说,有一个区别,巨大的 - 第一种方式是误导。这个函数不是构造函数(因为在Fortran中根本没有OOP构造函数),它是一个初始化器。


在主流OOP构造函数中负责顺序做两件事:

  1. 内存分配。
  2. 会员初始化。
  3. 让我们看一下用不同语言实例化类的一些例子。

    Java

    MyType mt = new MyType(1);
    

    隐藏了一个非常重要的事实 - 对象实际上是指向类类型的变量的指针。 C ++ 中的等效项将使用以下内容在堆上进行分配

    MyType* mt = new MyType(1);
    

    但是在两种语言中都可以看到,即使在语法级别上也会反映出两个构造函数。它由两部分组成:关键字new(分配)和构造函数名称(初始化)。在 Objective-C 语法中,这个事实更加强调:

    MyType* mt = [[MyType alloc] init:1];
    

    但是,很多时候,您可以看到其他形式的构造函数调用。如果在堆栈上分配C ++ 使用特殊(非常差)语法构造

    MyType mt(1);
    

    这实际上是如此误导,我们可以不考虑它。

    Python

    mt = MyType(1)
    

    事实上,对象实际上是一个指针,而且首先发生分配的事实是隐藏的(在语法级别)。这种方法叫做__init__! O_O如此误导。与那个相比,С++堆栈分配逐渐消失。 =)


    无论如何,在语言中使用构造函数的想法意味着能够使用某种特殊方法在一个语句中分配初始化。如果你认为这是“真正的OOP”方式,我会给你带来坏消息。甚至Smalltalk doesn't have constructors。它只是对类本身有new方法的约定(它们是元类的单例对象)。 Factory Design Pattern用于许多其他语言以实现相同的目标。

    我在某处读到Fortran中的模块概念受到Modula-2的启发。在我看来,OOP功能的灵感来自于Oberon-2。 Oberon-2中也没有构造函数。但是当然有使用预先声明的程序NEW的纯分配(如Fortran中的ALLOCATE,但ALLOCATE是语句)。分配后你可以(应该在实践中)调用一些初始化程序,这只是一个普通的方法。没什么特别的。

    因此,您可以使用某种工厂来初始化对象。这是你实际使用模块而不是单例对象所做的事情。或者最好说他们(Java / C#/ ...程序员)使用单例对象方法而不是普通函数,因为缺少后者(没有模块 - 没有办法让普通函数,只有方法)。

    您也可以使用类型绑定的SUBROUTINE。

    MODULE mymod
    
      TYPE mytype
        PRIVATE
        INTEGER :: x
        CONTAINS
        PROCEDURE, PASS :: init
      END TYPE
    
    CONTAINS
    
      SUBROUTINE init(this, i)
        CLASS(mytype), INTENT(OUT) :: this
        INTEGER, INTENT(IN) :: i
    
        IF(i > 0) THEN
          this%x = 1
        ELSE
          this%x = 2
        END IF
      END SUBROUTINE init
    
    END
    
    PROGRAM test
    
      USE mymod
    
      TYPE(mytype) :: x
    
      CALL x%init(1)
    
    END PROGRAM
    
    <{1}} INTENT(OUT) this SUBROUTINE的init似乎没问题。因为我们希望在分配后只调用一次这个方法。控制这个假设不会出错也可能是一个好主意。要向LOGICAL :: inited添加一些布尔标志mytype,请检查它是否为.false.并在首次初始化时将其设置为.true.,并在尝试重新初始化时执行其他操作。我绝对记得在谷歌小组中有一些关于它的帖子......我找不到它。

答案 1 :(得分:6)

我查阅了Fortran 2008标准的副本。这允许您定义与派生类型具有相同名称的通用接口。我的编译器(英特尔Fortran 11.1)不会编译代码,所以我不怀疑(没有2003标准的副本),这是Fortran 2003标准尚未实现的功能。

除此之外,您的程序中存在错误。你的功能声明:

  type(mytype) function init_mytype
    integer, intent(in) :: i

指定函数规范中不存在的参数的存在和意图,该参数可能应该重写为:

  type(mytype) function init_mytype(i)