2010-11-23 122 views
14

当前是否可以重写Fortran中的结构构造函数?我已经看到这样提出的例子(例如在Fortran 2003规格):如何覆盖fortran中的结构构造函数

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”与PROCEDURE属性冲突派生属性在(1))。 Fortran 2003示例的逐字副本会生成类似的错误。我已经在gfortran 4.4,ifort 10.1和11.1中试过了,它们都产生了相同的错误。

我的问题:这只是fortran 2003的一个未实现的功能吗?还是我实施这个不正确?

编辑:我遇到过这个问题的bug reportannounced patch gfortran。不过,我已经尝试过使用gcc46的11月版本,但没有运气和类似的错误。

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

回答

6

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

除此之外,您的程序中有错误。你的函数声明:

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

指定的存在和论证的意图是不存在的功能规范,这或许应该改写为:

type(mytype) function init_mytype(i) 
+0

谢谢,修复。为分心的错误道歉,这是一个匆忙的例子。 – 2010-11-24 10:36:18

17

Is it currently possible to override the structure constructor in Fortran?

不管怎么说即使使用你的方法也完全不是构造器重写。主要原因是结构构造器#OOP构造函数。有一些相似之处,但这只是另一个想法。

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

考虑这一事实考虑我完全不明白是什么

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

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

,什么是使用mymod模块内部接口块的整点之间的真正区别。

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


在主流的面向对象的构造函数负责顺序做两件事情:

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

让我们来看看实例化不同语言类的一些例子。

的Java

MyType mt = new MyType(1); 

一个非常重要的事实是隐藏的 - 事实的对象实际上是一个指向类类型的varibale。在C++相当于将是堆分配使用:

MyType* mt = new MyType(1); 

但在两种语言中可以看出,两个构造职责,即使在语法层面的体现。它由两部分组成:关键字new(分配)和构造函数名称(初始化)。在Objective-C的语法这个事实更是强调:

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

但很多时候,你可以看到构造函数调用的一些其他形式。在堆栈ç分配的情况下++使用特殊(很差)语法结构

MyType mt(1); 

这实际上是重大的误导性,我们可以直接不考虑它。

的Python

mt = MyType(1) 

两个事实对象实际上是一个指针和一个事实,即分配首先发生被隐藏(在语法级别)。而这种方法被称为... __init__! O_O如此误导。 С++堆栈分配与那个相比褪色。 =)


反正有构造的语言的想法意味着做在一个声明中分配初始化的能力,使用一些特殊的方法。如果你认为这是“真正的面向对象”方式,我对你有坏消息。即使Smalltalkdoesn't have constructors。它只是一个约定,对类本身有一个new方法(它们是元类的单例对象)。 Factory Design Pattern在许多其他语言中用于实现相同的目标。

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

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

您也可以使用type-bound 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 

INTENT(OUT)this ARG init子程序似乎是罚款。因为我们希望这种方法在分配后只调用一次。可能是一个好主意来控制这个假设不会错。要添加一些布尔标志LOGICAL :: initedmytype,检查它是否为.false.,并在第一次初始化时将其设置为.true.,并在尝试重新初始化时执行其他操作。我绝对记得有关Google Groups的一些主题......我无法找到它。

+2

谢谢你的澄清。我知道它不是纯粹的OOP意义上的构造器,类似的替代方法将完成大部分相同的事情。相反,这是p445(C.1.6)的一个近乎逐渐的例子,作者在其中一个规范工作草案中选择了这个例子来称作“结构构造器”。我想知道,这样的重写目前是否可以用于fortran的常见实现。但我会认真听取您的意见,再次感谢您。 – 2010-11-25 21:49:28