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

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

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

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

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

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

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

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

```fortran
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とセッタ、ゲッタを実装してある。

```fortran: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
```

```fortran: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