2

私は Fortran OOP の初心者であり、親および派生型の初期化でいくつかの問題に直面しています。object親の型(単語の使いすぎで申し訳ありません..) とその派生型を含む 1 つのモジュールがありcircle、これには余分なradiusフィールドがあります。

型を初期化する必要がある方法ではobject、半径に仮引数を使用する必要がありますが、これは避けたいと思います。現時点では私が持っているものはうまくいきますが、将来さらに派生型が必要になった場合、それはあまり実用的ではないように見えるので、これを行うためのより洗練された方法を知りたいと思いobjectます。

抽象的な親型として使用するobjectと、この意味で役立つと思いますか? または一般的な手順を使用しますが、その方法がよくわかりません。

コードは以下です。

module objectMod
  implicit none

  type :: object
     real,allocatable   :: x(:,:)           ! position vector (points) --- (M,{i,j})
     real               :: centre(2)        ! centre of the object
     integer            :: M=50             ! number of Lagrangian points of the object (default)
     real               :: eps=0.1          ! kernel of the surface (default)
   contains
     procedure :: init=>init_object
  end type object

contains

  subroutine init_object(a,centre,radius,M,eps)
    implicit none

    class(object),intent(inout)   :: a
    real,intent(in)               :: centre(2)
    integer,intent(in),optional   :: M
    real,intent(in),optional      :: eps
    real,intent(in),optional      :: radius ! ignored for object

    if(present(M)) a%M = M
    if(.not.allocated(a%x)) allocate(a%x(a%M,2))
    a%centre = centre
    if(present(eps)) a%eps = eps
  end subroutine init_object
end module objectMod

module geomMod
  use objectMod
  implicit none
  real,parameter :: PI = 3.14159265

  type,extends(object) :: circle
     real              :: radius    ! radius
   contains
     procedure :: init=>init_circle
  end type circle

contains

  subroutine init_circle(a,centre,radius,M,eps)
    implicit none
    class(circle),intent(inout) :: a
    real,intent(in)             :: centre(2)
    real,intent(in),optional    :: radius
    integer,intent(in),optional :: M
    real,intent(in),optional    :: eps

    integer :: i
    real    :: dtheta

    ! object type attributes initialization
    a%centre = centre
    if(present(M)) a%M = M
    if(.not.allocated(a%x)) allocate(a%x(a%M,2))
    if(present(eps)) a%eps = eps
    ! circle type attributes initialization
    a%radius = radius

    dtheta = 2.*PI/real(a%M-1)
    do i = 1,a%M
      a%x(i,1) = a%radius*cos(dtheta*(i-1))+a%centre(1)
      a%x(i,2) = a%radius*sin(dtheta*(i-1))+a%centre(2)
    end do
  end subroutine init_circle
end module geomMod
4

1 に答える 1

1

あなたがしている間違いは、コンストラクターを型バインド プロシージャとして作成することです。引数リストが準拠しなければならないという要件は、あなたに反します。

型バインド プロシージャは、コンストラクタ (または初期化子) にとって適切なツールではありません。

Fortran では、オブジェクトのインスタンスを返す関数を使用してオブジェクトを初期化します。

function init_object(centre,M,eps) result(a)
  type(object) :: a
  real,intent(in)               :: centre(2)
  integer,intent(in),optional   :: M
  real,intent(in),optional      :: eps
  !NO radius
end function init_object


interface object
  procedure init_object
end interface



....



obj = object(my_centre, my_m, my_eps)

これは、デフォルトの構造コンストラクターの呼び出し方法でもあります。


いくつかのオンラインチュートリアルから例を挙げたようです。この例は設計が悪いと思います。同意しない場合は、それがもたらすこれらの問題に対処する必要があります。


したがって、基本的には、コンストラクターの代わりに初期化メソッドが必要です (コンストラクターの代わりに初期化メソッドを使用する理由を参照してください) 。Objective-C はそのようなものを使用します https://www.binpress.com/tutorial/objectivec- lesson-11-object-initialization/76ですが、最近の Swift は代わりにコンストラクターを使用しています。)

この方法でジェネリックを使用できます。

    module types

        type t1
          integer :: i
        contains
          generic :: init => init_t1
          procedure, private :: init_t1
        end type

        type, extends(t1) :: t2
          integer :: j
        contains
          generic :: init => init_t2
          procedure, private :: init_t2
        end type

        type, extends(t2) :: t3
          integer :: k
        contains
          generic :: init => init_t3
          procedure, private :: init_t3
        end type

    contains


      subroutine init_t1(self, i)
        class(t1) :: self
      end subroutine

      subroutine init_t2(self, i, j)
        class(t2) :: self
      end subroutine

      subroutine init_t3(self, i, j, k)
        class(t3) :: self
      end subroutine

    end module

私の意見では、これは明らかに醜く、非 Fortranic ですが、あなたが望むことはできます。

エラーメッセージを発行する何かでオーバーロードして、ユーザーが誤って間違ったバージョンを呼び出さないように、特別な注意を払う必要があります。

私のアドバイスは、主流に慣れている人を混乱させる独自の方法を発明するのではなく、一般的なパターンに従うことです.

于 2016-03-16T14:46:33.393 に答える