目前无法在Fortran中覆盖结构构造函数。即使使用您的方法,也完全不涉及构造函数重写。主要原因是结构构造函数与面向对象编程(OOP)构造函数有一些相似之处,但这只是另一个想法。
您无法在初始化表达式中使用非内置函数。您只能使用常量、数组或结构构造函数、内置函数等。有关更多信息,请查看Fortran 2003草案中的7.1.7初始化表达式。
考虑到这一事实,我完全不理解以下内容的真正区别:
type(mytype) :: x
x = mytype(0)
并且
type(mytype) :: x
x = init_mytype(0)
我需要在mymod模块中使用INTERFACE块,这有什么意义呢?
说实话,这两种方法是有区别的,而且区别很大——第一种方法是误导性的。这个函数不是构造函数(因为Fortran中根本没有面向对象的构造函数),它是一个初始化器。
在主流的面向对象编程中,构造函数负责顺序执行两件事:
- 内存分配。
- 成员初始化。
让我们来看一些不同语言中实例化类的示例。
在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__
!太具有误导性了。与之相比,C ++的堆栈分配就显得逊色了。=)
无论如何,语言中有“构造函数”的想法都意味着使用某种特殊的方法可以在一条语句中执行“分配和初始化”,如果您认为这是“真正的OOP”方式,我有一个不好的消息。即使
Smalltalk 没有构造函数。它只是在类本身上有一个
new
方法的约定(它们是元类的单例对象)。
工厂设计模式用于许多其他语言来实现相同的目标。
我曾经读过Fortran中模块概念的灵感来自Modula-2。对我来说,面向对象的特性似乎受到了
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
init
子程序中this
参数的INTENT(OUT)
看起来没问题。因为我们希望这个方法只被调用一次,而且是在分配之后立即调用。也许控制这个假设不会出错是个好主意。可以向mytype
添加一个布尔标志LOGICAL :: inited
,检查它是否为.false.
,并在第一次初始化时将其设置为.true.
,以及在尝试重新初始化时执行其他操作。我肯定记得Google Groups上有一些关于这方面的讨论...但我找不到它了。