14

現在、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 でこれを試しましたが、すべて同じエラーが発生します。

私の質問: これは fortran 2003 の実装されていない機能ですか? または、これを間違って実装していますか?

編集:この問題に関する gfortranのバグ レポート発表済みのパッチを見つけました。ただし、gcc46 の 11 月のビルドを使用してみましたが、運が悪く、同様のエラーが発生しました。

編集 2: 上記のコードは、Intel Fortran 12.1.0 を使用して動作するようです。

4

2 に答える 2

19

現在、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 コンストラクターでは、次の 2 つのことを順番に実行します。

  1. メモリ割り当て。
  2. メンバーの初期化。

さまざまな言語でクラスをインスタンス化する例をいくつか見てみましょう。

Javaの場合:

MyType mt = new MyType(1);

非常に重要な事実が隠されています - オブジェクトが実際にはクラス型の変数へのポインタであるという事実です。C++で同等のものは、次を使用したヒープへの割り当てになります

MyType* mt = new MyType(1);

しかし、どちらの言語でも、構文レベルでも 2 つのコンストラクターの義務が反映されていることがわかります。これは、キーワード new (割り当て) とコンストラクター名 (初期化) の 2 つの部分で構成されます。Objective-C構文では、この事実がさらに強調されます。

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

ただし、多くの場合、他の形式のコンストラクター呼び出しを確認できます。スタックへの割り当ての場合、C++は特殊な (非常に貧弱な) 構文構造を使用します

MyType mt(1);

これは実際には非常に誤解を招くため、考慮できません。

Python

mt = MyType(1)

オブジェクトが実際にはポインターであるという事実と、割り当てが最初に行われるという事実の両方が (構文レベルで) 隠されています。そして、このメソッドは...と呼ばれています__init__!O_O とても誤解を招く。С++ スタック割り当ては、それと比較してフェードします。=)


とにかく、言語にコンストラクターを持つという考えは、何らかの特別な種類のメソッドを使用して、1 つのステートメントで割り当てと初期化を実行できることを意味します。そして、これが「真の OOP」だと思うなら、悪いニュースがあります。Smalltalk にもコンストラクタはありません。クラス自体にメソッドを持つのは単なる慣例newです (それらはメタ クラスのシングルトン オブジェクトです)。Factory Design パターンは、同じ目標を達成するために他の多くの言語で使用されています。

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

INTENT(OUT)SUBROUTINEのfor thisarg は問題ないようです。initこのメソッドは、割り当て直後に 1 回だけ呼び出されることが想定されているためです。この仮定が間違っていないことを制御するのは良い考えかもしれません。LOGICAL :: initedブール値フラグをに追加するには、最初の初期化時にmytypeそうであるかどうかを確認.false.してに設定し.true.、再初期化の試行時に何か他のことを行います。Google グループでそれに関するスレッドをいくつか覚えていますが、見つかりません。

于 2010-11-25T20:13:20.917 に答える
6

Fortran 2008 標準のコピーを参考にしました。これにより、派生型と同じ名前のジェネリック インターフェイスを定義できます。ただし、私のコンパイラ (Intel Fortran 11.1) はコードをコンパイルしないので、これが Fortran 2003 標準のまだ実装されていない機能であると疑っています (2003 標準のコピーが手元にないため)。

それに加えて、プログラムにエラーがあります。あなたの関数宣言:

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

関数仕様に存在しない引数の存在と意図を指定します。おそらく次のように書き換える必要があります。

  type(mytype) function init_mytype(i)
于 2010-11-24T07:58:09.433 に答える