LoginSignup
12
10

More than 5 years have passed since last update.

続・fortranでもオブジェクト指向したい!「継承と抽象クラス」

Last updated at Posted at 2018-06-21

前回: https://qiita.com/Bluepost59/items/ca560c49a8c19484db9d

果てしなく間が空いてしまったが、今回は一歩進んで継承と抽象クラスについてまとめたいと思う。

※「そもそも抽象クラスって何」って人はこれを見て下さい
https://qiita.com/Bluepost59/items/eef6f48fdd322b0b9791

継承

継承は簡単で、typeの後にextendsキーワードをつけるだけでよい。

type,extends(parent_class) :: child_class
   integer param1
   !...
contains
   procedure :: method1 => child_method1
   !...
end type child_class

抽象クラス

抽象クラス自体はtypeにabstract属性を付けるだけでよい。

関数やサブルーチンをつけるところがかなりややこしい。procedure文だけでは不十分で、interface文で引数や戻り値を設定する必要がある。

type,abstract :: absclass
   integer param2
   !...
contains
   procedure(absmethod1),deferred :: method1
   procedure(absmethod2),deferred :: method2
   !...
end type absclass

!引用仕様(戻り値、引数)の定義
interface
   subroutine absmethod1(self,subparam)
      import absclass
      class(absclass) self
      integer subparam
   end subroutine absmethod1

   double precision function absmethod2(self,subparam)
      import absclass
      !...
   end function absmethod2
end interface

ポイントはクラス本体の宣言と引用仕様の宣言が相互参照のようになっているところだ。はっきりいって謎な仕様ではある。

何はともあれ、これで抽象クラスが定義された。この子クラスではmethodをオーバーライドしなければコンパイルエラーとなる。

具体例

抽象クラスgirlと、それを継承したクラスidolを実装した。girlはnameおよびそのセッタとゲッタ、idolはそれに加えてgroupとセッタ、ゲッタを実装してある。

mod_idol.f90
module mod_idol
  implicit none

!---------------------------------------------------
! 抽象クラス girl
  type,abstract :: girl
     private
     character(len=60) :: name = "noname"
   contains
     procedure(girl_set_name),deferred :: set_name
     procedure(girl_get_name),deferred :: get_name
  end type girl

! 引用仕様の宣言
  interface
     subroutine girl_set_name(self,str)
       import girl
       class(girl) self
       character(len=60) str
     end subroutine girl_set_name

     character(len=60) function girl_get_name(self)
       import girl
       class(girl) self
     end function girl_get_name
  end interface
!---------------------------------------------------
! クラス idolの宣言部 
  type,extends(girl) :: idol
     private
     character(len=60) group
   contains
     procedure :: set_name => idol_set_name
     procedure :: get_name => idol_get_name
     procedure :: join => idol_join
     procedure :: get_group => idol_get_group
  end type idol

contains
!---------------------------------------------------
! クラス idolの実装部
  subroutine idol_set_name(self,str)
    class(idol) self
    character(len=60) str
    self%name = str
  end subroutine idol_set_name

  character(len=60) function idol_get_name(self)
    class(idol) self
    idol_get_name = trim(self%name)
  end function idol_get_name

  subroutine idol_join(self,group)
    class(idol) self
    character(len=60) group
    self%group = group
  end subroutine idol_join

  character(len=60) function idol_get_group(self)
    class(idol) self
    idol_get_group = trim(self%group)
  end function idol_get_group

end module mod_idol
main.f90
program main
  use mod_idol
  implicit none

  type(idol) :: myidol

  character(len=60) :: myname = "Momoka"
  character(len=60) :: myunit = "momo_pear_berry"

  call myidol%set_name(myname)
  call myidol%join(myunit)

  write(6,*) "name:", myidol%get_name()
  write(6,*) "unit:", myidol%get_group()

end program main

gist: https://gist.github.com/Bluepost59/be1975d070e3451c0aa51ab4d6d160f5

感想

  • コードがえげつなく長くなってしまった。もう少し短く書けないものか。
  • とはいえ古文と揶揄されるfortranでもOOPが一通り実装できたので満足。
  • 正直C++の方が楽

参考サイト

NAG
http://www.nag-j.co.jp/nagfor/np52_manual/np52_manual_10_2.html

IBM
https://www.ibm.com/support/knowledgecenter/ja/SSGH4D_15.1.0/com.ibm.xlf151.aix.doc/language_ref/abstracttypes.html

12
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
10