Fortran/オブジェクト指向プログラミング
表示
< Fortran
オブジェクト指向プログラミング
[編集]モジュール
[編集]概要
[編集]データはmodule
内にまとめることができます。一般的な形式は以下の通りです。
module <name> [use <module_names>] [<declarations>] contains [<subroutines and functions>] end module [<name>]
データへのアクセス
[編集]3つのアクセスプロパティがあります: public, private, protected
。
public
: 外部のコードから読み書きが可能です。private
: 外部のコードからアクセスできません。public, protected
: 外部のコードから読み取りが可能です。
他のコードでモジュールを使用する
[編集]モジュールの公開データを外部のコードに含めることができます。 3つの方法があります。
use <moduleName>
: すべての公開データとメソッドが含まれますuse <moduleName>, <renames>
: すべての公開データとメソッドが含まれますが、一部の公開データやメソッドの名前を変更しますuse <moduleName>, only: <subset>
: 一部の公開データとメソッドのみが含まれます
例
[編集]概要
[編集]module test_m implicit none private ! すべてのデータはデフォルトで非公開です。 ! これらの手続きはpublicに設定され、モジュールの外部からアクセス可能です。 public print_coords, set_coords real :: x, y ! モジュールの外部からはアクセスできません。 contains subroutine print_coords print *, "x, y", x, y end subroutine subroutine set_coords(new_x, new_y) real, intent(in) :: new_x, new_y x = new_x y = new_y end subroutine end module program main use test_m ! "test_m"モジュールをインポートします implicit none call set_coords(1.0, 1.0) ! test_modからpublicな手続きを呼び出します。 call print_coords end program
データアクセス
[編集]module data_access_m implicit none private public a, b protected b private c integer :: a = 1 integer :: b = 1 integer :: c = 1 end module program main use data_access_m ! publicオブジェクトへのアクセスは可能です。 print *, a ! publicオブジェクトの編集は可能です。 a = 2 ! protectedオブジェクトへのアクセスは可能です。 print *, b ! protectedオブジェクトの編集はできません。 !b = 2 <- エラー ! privateオブジェクトへのアクセスはできません !print *, c <- エラー ! privateオブジェクトの編集はできません !c = 2 <- エラー end program
モジュールの使用
[編集]module test_module implicit none private integer, public :: a = 1 integer, public, protected :: b = 1 integer, private :: c = 1 end module test_module !> test_moduleのすべての公開データをインポートします。 program main use test_module print *, a, b end program main !> すべてのデータをインポートし、名前を変更します。 program main use test_module, better_name => a ! 新しい名前が利用可能です。 print *, better_name ! 古い名前はもう利用できません。 !print *, a <- エラー end program main !> 公開データのサブセットのみをインポートします。 program main use test_module, only : a ! aだけがロードされます。 print *, a ! bはロードされません。 !print *, b <- エラー end program main
サブモジュール
[編集]モジュールはサブモジュールを使用して拡張することができます。複数の利点があります
- 大きなモジュールの分割
- インターフェース定義と実装の分割により、依存するモジュールが実装が変更されても再コンパイルする必要がありません
- 2つのモジュールがお互いからデータを必要とする場合。
例
[編集]定義と実装の分割
[編集]!> 円に関する簡単なモジュール module circle_mod implicit none private public :: area, radius real :: radius real, parameter :: PI = 3.1415 interface ! インターフェースブロックが必要です。サブモジュール経由で実装される各機能には、ここにエントリが必要です。 module function area() ! 重要です。"module"キーワードに注意してください。 real :: area end function end interface end module submodule (circle_mod) circle_subm ! サブモジュール (親モジュール) 子モジュール. contains module function area() ! 再び "module" キーワード。 area = PI*radius**2 end function end submodule program main use circle_mod implicit none radius = 1.0 print *, "area:", area() end program
派生データ型
[編集]Fortranでは、他の構造から構造を派生させることができます。これを「派生データ型」と呼び、派生型は親型の特徴を持ち、新たに追加されたものも持ちます。一般的な構文は以下の通りです。
type, extends(<parentTypeName>) :: <newTypeName> <definitions> end type
次の例は、会社内の異なるタイプの人々を示しています。
module company_data_mod implicit none private public phone_type, address_type, person_type, employee_type, salaried_worker_type, hourly_worker_type type phone_type integer :: area_code, number end type type address_type integer :: number character (len=:), allocatable :: street, city character (len=2) :: state integer :: zip_code end type type person_type character (len=:), allocatable :: name type (address_type) :: address type (phone_type) :: phone character (len=:), allocatable :: remarks end type type, extends (person_type) :: employee_type integer :: phone_extension, mail_stop, id_number end type type, extends (employee_type) :: salaried_worker_type real :: weekly_salary end type type, extends (employee_type) :: hourly_worker_type real :: hourly_wage, overtime_factor, hours_worked end type end module program main use company_data_mod implicit none type (hourly_worker_type) :: obj end program
デストラクタ
[編集]オブジェクトが自動的に削除される前に呼び出される手続きを定義することができます。これはfinal
ステートメントで行われます。次の例を参照してください。
module person_m implicit none type person integer, allocatable :: numbers(:) contains final :: del end type contains subroutine del(this) !! 派生型のデストラクタの例。 allocatables は !! 自動的に解放されるので、これは final の使用法を示すだけです。 type (person), intent (inout) :: this if (allocated(this%numbers)) deallocate (this%numbers) end subroutine end module
抽象基底型と遅延手続き
[編集]基底型をabstract
として設定することで、その型のオブジェクトを初期化できなくなりますが、その型のサブタイプを派生させることはできます(extends
を使用)。サブタイプで定義する必要のある特定の手続きは、deferred
プロパティを持つ必要があり、明示的なインターフェースが必要です。
以下の例はその使用方法を示しています。
module shape_m implicit none type, abstract :: shape real :: a, b contains procedure :: print => shape_print procedure (area_shape), deferred :: area end type interface real function area_shape(this) import :: shape class (shape), intent (in) :: this end function end interface contains subroutine shape_print(this) class (shape), intent (in) :: this print *, 'a,b', this%a, this%b end subroutine end module module line_m use shape_m implicit none private public line type, extends (shape) :: line contains procedure :: area end type contains real function area(this) class (line), intent (in) :: this area = abs(this%a - this%b) end function end module module rectangle_m use shape_m implicit none private public rectangle type, extends(shape) :: rectangle contains procedure :: area end type contains real function area(this) class (rectangle), intent (in) :: this area = this%a * this%b end function end module program main use line_m use rectangle_m implicit none type (line) :: l type (rectangle) :: r ! line l%a = 2.0 l%b = 4.0 print *, "line ... " call l%print print *, "-> from: ", l%a print *, "-> to: ", l%b print *, "-> length:", l%area() ! rectangle r%a = 3.0 r%b = 5.0 print * print *, "rectangle ..." call r%print print *, "-> side a:", r%a print *, "-> side b:", r%b print *, "-> area: ", r%area() end program
ポリモーフィックポインタ
[編集]allocate
文での型定義とselect type
環境を使用して、子クラスへのポインタを作成することができます。
以下の例ではその使用方法を強調しています。
module shape_m implicit none type, abstract :: shape ! 親クラスを実装するために使用される空のクラスです。 ! abstract の理由: TYPE(!) shapeのオブジェクトは存在しないはずです。 ! ポリモーフィックCLASSのインスタンスのみ。 end type end module module line_m use shape_m implicit none type, extends (shape) :: line ! 1つの属性を持つ子クラスです。 ! extends(shape)の理由: ポリモーフィックshapeポインタは ! この型のオブジェクトを指すことができます。 real :: length end type end module module rectangle_m use shape_m implicit none type, extends (shape) :: rectangle ! 別の属性を持つ子クラスです ! extends(shape)の理由: (lineの説明を参照) real :: area end type end module program main use rectangle_m use line_m implicit none class (shape), allocatable :: sh ! 親クラスへのポインタ。 ! allocate (line :: sh) allocate (rectangle :: sh) ! 子型を使用して割り当てます select type (x => sh) ! アソシエーションブロック。"x"は子オブジェクトへのポインタおよびその型になります(!!) type is (line) ! 正しい子タイプを選択します (allocateステートメントで使用したもの) x%length = 1.0 print *, 'line length', x%length type is (rectangle) x%area = 2.0 print *, 'rectangle area', x%area ! class is () ! クラスを使用して選択します。 class default ! 何も適用されなかった場合。 error stop 'class/type not specified!' end select end program
用語のまとめ(和訳独自)
[編集]ここでは、Fortranに関連するオブジェクト指向プログラミングの用語をまとめます。
- モジュール (Module):
- データや手続きをまとめた単位。
- カプセル化や再利用性を促進する。
module
ブロックで宣言し、end module
で終了する。
- データアクセスプロパティ:
public
,private
,protected
の3つのアクセスプロパティがある。public
: 外部コードから読み書き可能。private
: 外部コードからアクセス不可。protected
: 外部コードから読み取り可能。
- モジュールの使用:
- 外部のコードでモジュールのデータや手続きを使用する方法。
use <moduleName>
でモジュールをインポートする。use <moduleName>, only: <subset>
で一部のデータや手続きのみをインポートする。
- サブモジュール (Submodule):
- 大規模なモジュールをさらに分割するための仕組み。
- インターフェースと実装を分離し、依存関係を管理する。
- 派生データ型 (Derived Data Type):
- 他のデータ型から派生した新しいデータ型。
type, extends(<parentTypeName>) :: <newTypeName>
の形式で宣言する。
- デストラクタ (Destructor):
- オブジェクトが削除される前に実行される手続き。
- リソースの解放や後処理を行うために使用される。
- 抽象基底型 (Abstract Base Type):
- インスタンスを作成できない抽象的な型。
- 派生型は抽象基底型から派生して具体的な型を作成する。
- 遅延手続き (Deferred Procedure):
- 派生型で実装する必要のある手続き。
- 抽象基底型で定義され、具体的な型で実装される。
- ポリモーフィックポインタ (Polymorphic Pointer):
- 異なる型のオブジェクトに対して同じポインタを使用できる仕組み。
- 実行時に異なる型のオブジェクトを操作するために使用される。
これらの用語を理解することで、Fortranでオブジェクト指向プログラミングをより効果的に行うことができます。