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

mar*_*ard 14 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
Run Code Online (Sandbox Code Playgroud)

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

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

编辑:我遇到过一个错误报告和gfortran关于这个问题的公告补丁.但是,我尝试使用11月版的gcc46没有运气和类似的错误.

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

Wil*_*cat 18

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

反正即使使用你的做法是完全不是构造函数重载.主要原因是结构构造函数#OOP构造函数.有一些相似之处,但这只是另一个想法.

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

考虑到这一事实,我完全不明白它们之间的真正区别是什么

type(mytype) :: x
x = mytype(0)
Run Code Online (Sandbox Code Playgroud)

type(mytype) :: x
x = init_mytype(0)
Run Code Online (Sandbox Code Playgroud)

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

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


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

  1. 内存分配.
  2. 成员初始化.

让我们看一下用不同语言实例化类的一些例子.

Java中:

MyType mt = new MyType(1);
Run Code Online (Sandbox Code Playgroud)

隐藏了一个非常重要的事实 - 对象实际上是指向类类型的变量的指针.C++中的等价物将使用以下方式在堆上进行分配:

MyType* mt = new MyType(1);
Run Code Online (Sandbox Code Playgroud)

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

MyType* mt = [[MyType alloc] init:1];
Run Code Online (Sandbox Code Playgroud)

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

MyType mt(1);
Run Code Online (Sandbox Code Playgroud)

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

Python中

mt = MyType(1)
Run Code Online (Sandbox Code Playgroud)

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


总之,具有理念构造的语言暗示做的能力分配的初始化在一条语句中使用一些特殊的方法.如果你认为这是"真正的OOP"方式,我会给你带来坏消息.即使Smalltalk 也没有构造函数.它只是一个new在类本身上有一个方法的约定(它们是元类的单例对象).该工厂设计模式在许多其他语言来达到同样的目的.

我在某处读到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
Run Code Online (Sandbox Code Playgroud)

INTENT(OUT)对于SUBROUTINE的thisarg init似乎没问题.因为我们希望在分配后只调用一次这个方法.控制这个假设不会出错也可能是一个好主意.要添加一些布尔标志LOGICAL :: initedmytype,检查它是否.false.将其设置为.true.在第一次初始化,并做一些尝试的重新初始化别人.我绝对记得Google网上有一些关于它的帖子......我找不到它.

  • 谢谢你的澄清.我知道它不是纯粹的OOP意义上的构造函数,并且类似的替代方法将完成大部分相同的事情.相反,这是p445(C.1.6)的一个近乎逐字的例子,作者选择在其中一个规范工作草案中称之为"结构构造函数".我想知道在fortran的常见实现中是否存在这样的重写.但我会把你的建议铭记于心,再次感谢你. (2认同)

Hig*_*ark 6

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

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

  type(mytype) function init_mytype
    integer, intent(in) :: i
Run Code Online (Sandbox Code Playgroud)

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

  type(mytype) function init_mytype(i)
Run Code Online (Sandbox Code Playgroud)