9.2 オブジェクト指向プログラミング
9.2.1 型拡張
型拡張はオブジェクト指向の最初のフェーズである継承と多相オブジェクト機能を 提供します。9.2.1.1 型の拡張 [5.0]
SEQUENCE型とBIND(C)型を除くすべての構造型はEXTENDSキーワードを使って拡張すること ができます。 (SEQUENCE型とBIND(C)型は組込み型と同様に“拡張不可能”であるのに対し、他の すべての構造型は“拡張可能”です。) 拡張された型は親型のすべての成分を継承し、その上に成分を追加できます。例:
TYPE point REAL x,y END TYPE TYPE,EXTENDS(point) :: point_3d REAL z END TYPE型 point_3d は x, y, z 成分を持っています。 それに加えて継承部分を参照する point 成分を持っています。 この“親成分”は継承された成分と“継承結合”されています。例えば point%x 成分は x 成分と同一です。
しかし型を拡張する際に新しい成分を追加する必要はありません。例えば
TYPE,EXTENDS(point) :: newpoint END TYPEは新しい型 newpoint を定義しますが、この型はpoint(と結合された親成分) と全く同じ成分を持っています。 同様に成分を全く含まない型であっても問題はありません:
TYPE empty_type END TYPEこの例では成分を全く含んでいない拡張可能な(しかし拡張されていない)型 empty_type を宣言しています。
9.2.1.2 多相変数 [5.0]
多相変数はTYPEキーワードではなく、CLASSキーワードにより宣言されたポインタ、 割付け配列、もしくは仮引数です。 CLASS(typename)変数は、TYPE(typename) 型とtypename のすべての拡張型とから構成されるクラスに属する任意の型を 取ることができます。例:
REAL FUNCTION bearing(a) CLASS(point) a bearing = atan2(a%y,a%x) END関数 bearing は TYPE(point) オブジェクトもしくは TYPE(point_3d) オブジェクトに適用できます(実際にはTYPE(point) の任意の拡張型オブジェクトに適用できます)。
9.2.1.3 型選択 [5.0]
SELECT TYPE 構文により多相変数の動的な型のテストとその変数の拡張成分へ のアクセスが行えます。例:
CLASS(t) x ... SELECT TYPE(p=>x) TYPE IS (t1) ! ! This section is executed only if X is exactly of TYPE(t1), not an ! extension thereof. P is TYPE(t1). ! TYPE IS (t2) ! ! This section is executed only if X is exactly of TYPE(t2), not an ! extension thereof. P is TYPE(t2). ! CLASS IS (t3) ! ! This section is executed if X is of TYPE(t3), or of some extension ! thereof, and if it is not caught by a more specific case. P is CLASS(t3). ! END SELECT‘SELECT TYPE(x)’ は‘SELECT TYPE(x=>x)’の短縮形 です。
9.2.1.4 無限多相性 [5.2]
‘CLASS(*)’ である変数は無限多相変数です。 無限多相変数は型を持ちませんが、拡張不可能型や組込み型(および種別)を含む どのような型でも取ることができます。 割付け、解放、ポインタ代入を除き、無限多相に対して演算を行うには、まず最初 にその型をSELECT TYPEで知る必要があります。例:
CLASS(*),POINTER :: x CHARACTER(17),TARGET :: ch x => ch SELECT TYPE(x) TYPE IS (COMPLEX(KIND=KIND(0d0))) PRINT *,x+1 TYPE IS (CHARACTER(LEN=*)) PRINT *,LEN(x) END SELECTCHARACTERの場合、長さは ‘*’ と指定されなくてはならず、それ は多相が関連付けられているものから自動的に認識される点に注意してください。
拡張不可能な型(BIND(C) もしくは SEQUENCE)の場合には、
SELECT TYPE を使用して型を調べることができません。その代り安全ではない
ポインタ代入が認められています。
例:
TYPE t SEQUENCE REAL x END TYPE CLASS(*),POINTER :: x TYPE(t),POINTER :: y ... y => x ! Unsafe - the compiler cannot tell whether X is TYPE(t).
9.2.1.5 アドホックな型比較 [5.3]
多相オブジェクトの動的な型を比較するために2つの新たな組込み関数が用意されて います。
EXTENDS_TYPE_OF(A,MOLD)
SAME_TYPE_AS(A,B)
引数は拡張可能型のオブジェクトでなければなりません(ただし多相である必要は ありません)。 SAME_TYPE_AS は A と B が同じ動的な型を持っている場合 にのみ .TRUE. を返します。 EXTENDS_TYPE_OF は A の動的な型が MOLD の動的な型と同 じ、もしくはその拡張である場合にのみ .TRUE. を返します。 MOLD が割付けられていない無限多相(CLASS(*))であった場合には、 Aの状態に関わりなく結果は真となります。
引数は割付けられていない状態もしくは遊離状態にあっても問題ありませんが、 未定義な結合状態のポインタであることは許されません。
可能な場合にはこれらの組込み関数の使用は避け、型チェックには代りに SELECT TYPE を使用することが推奨されます。
9.2.2 型付き割付け [5.1]
ALLOCATE 文でtype-spec の指定が可能になりました。これにより割付 けに際して動的な型(と必要ならば型パラメタ)の指定が可能です。 type-spec は割付け並びの前に指定され、それとは2つのコロンで区切られま す。例えば T が拡張可能型で ET が T の拡張とするとき、
CLASS(t),POINTER :: a(:) ALLOCATE(et::a(100))は動的な型 ET を持つように A を割付けます。 ALLOCATE 文内のtype-spec は構造型に対する TYPE キーワード を省略する点に注意して下さい(TYPE IS 文と CLASS IS 文の場合と 同様です)。
無限多相オブジェクトは組込み型を含むどのような型としても割付けできます。 例えば
CLASS(*),POINTER :: c,d ALLOCATE(DOUBLE PRECISION::c) READ *,n ALLOCATE(CHARACTER(LEN=n)::d)は倍精度実数となるように C を割付け、長さ N の CHARACTER となるように D を割付けます。
型付き割付けは多相変数及び無指定長 (LEN=:) の CHARACTER 変数 を割付ける場合にのみ有用です。 非多相変数に対しては、type-spec は宣言された型と、CHARACTER 型 で無指定長でない場合には同一文字列長を持つことを指定しなくてはなりません。 割付けオブジェクトがアスタリスクの文字長を持つ仮引数でない場合には、文字長 をアスタリスク(CHARACTER(LEN=*))として指定することはできません (その反対も然りです)。
最後にtype-spec は一つしかないので、それは割付け並び中のすべての項目と 整合性が維持されていなくてはなりません。
9.2.3 元指定割付け (クローニング) [5.1]
ALLOCATE 文では新たに SOURCE= 指定子の指定が可能となりました。 割付けされた要素の動的な型と値が指定子の式から取得されます。 構造型が型パラメタ(q.v.)を持つ場合、無指定型パラメタの値は元となる式より 取得され、それ以外の型パラメタの値は一致していなくてはなりません。 これは構造型に限ったことではありません。割付けされる要素が無指定長 (LEN=:)の CHARACTER 型である場合には、文字長は元の式から取 得されます。SOURCE= 指定子が指定された場合、一つの要素のみが割付け可能です。 配列の割付けを行う場合、配列形状は元となる式から取得されないので通常の方法 で指定する必要があります。 元となる式が配列の場合、それは割付け対象の配列と同じ形状でなければなりません。
例:
CLASS(*),POINTER :: a,b ... ALLOCATE(a,SOURCE=b)割付けされた変数 A は、B の現在の型が何であれ、B の “クローン”となります。
9.2.4 型結合手続き [5.1]
型結合手続きは型の型自身に関する操作を一まとめにするための方法、及び多相変数 の動的な型に依存した手続きの動的呼出し機能を提供します。9.2.4.1 型結合手続き部
型定義の型結合手続き部は CONTAINS 文により成分と区切られます。 型結合手続きのデフォルトのアクセシビリティはたとえ成分が非公開であっても公開 となります。これは PRIVATE 文を CONTAINS の後に指定することに より変更可能です。9.2.4.2 個別型結合手続き
個別の、無指定ではない型結合手続きの宣言の構文は次の通りです:PROCEDURE [[,binding-attr-list]::] binding-name [=>procedure-name]
型結合手続きの名前はbinding-name で、それを実装する実手続きの名前は procedure-name です。 オプショナルである=>procedure-name が省略された場合には、実手続き はbindingと同じ名前になります。
型結合手続きはその型のオブジェクトから呼び出されます。
例:
CALL variable(i)%tbp(arguments)通常、呼出し変数は追加の引数“渡されたオブジェクトの仮引数”として渡され ます。デフォルトではこれが実手続きの第一番目の仮引数となるので、引数並びの最初 の引数は第2番目の引数となります。 渡されたオブジェクトの仮引数はPASS(argument-name) 属性を持 つ型結合手続きを宣言することによって変更することが可能です。この場合、変数は 名前付き引数として渡されます。PASS 属性をデフォルト(最初の引数)の確認 のために使用することもできます。NOPASS 属性はオブジェクトを引数として渡 すことを阻止します。 渡されたオブジェクトの仮引数はその型の多相スカラ変数でなければなりません。 例えば CLASS(t) self です。
型を拡張する場合、新しい型は古い型の個々の型結合手続きを継承するか、もしくは それらをbf{オーバーライド}します。 オーバーライドする手続きは古い手続きと整合性が取れていなくてはなりません。 特に、新しい型を持つ渡されたオブジェクトの仮引数を除くと、それぞれの仮引数は 同じ型を持っている必要があります。 NON_OVERRIDABLE として宣言された型結合手続きは型拡張においてオーバー ライドできません。
型結合手続きが呼び出される場合に、どの実手続きをコールするかを決めるのは変数 の動的な型です。
型結合手続きが持ちうる他の属性には PUBLIC, PRIVATE, DEFERRED があります(最後のものは後述する抽象型にのみ関連します)。
9.2.4.3 総称型結合手続き
通常の総称手続きが個別手続きの集合であるのと同様、総称型結合手続きは個別型 結合手続きの集合です。 これは GENERIC 文により宣言します。例:
GENERIC :: generic_name => specific_name_1, specific_name_2, specific_name_3総称型結合手続きは演算子であっても代入文であっても構いません。
例:
GENERIC :: OPERATOR(+) => add_t_t, add_t_r, add_r_tこのような型結合総称演算子は NOPASS 属性を持つことができません。 渡されたオブジェクトの仮引数の動的な型が呼び出される実手続きを決定します。
型を拡張する場合、新しい型は例外なしにすべての総称型結合手続きを継承します。 新しい型は個別手続きを追加することによって総称を拡張することが可能です。 総称の手続きをオーバーライドする場合には個別型結合手続きをオーバーライドし ます。例えば
TYPE mycomplex ... CONTAINS PROCEDURE :: myc_plus_r => myc1_plus_r PROCEDURE,PASS(B) :: r_plus_myc => r_plus_myc1 GENERIC :: OPERATOR(+) => myc_plus_r, r_plus_myc END TYPE ... TYPE,EXTENDS(mycomplex) :: mycomplex_2 ... CONTAINS PROCEDURE :: myc_plus_r => myc2_plus_r PROCEDURE,PASS(B) :: r_plus_myc => r_plus_myc2 END TYPEにおいて、型 mycomplex_2 は総称演算子 ‘+’ を継承します。 総称 (+) の呼出しにより個別型結合手続きが呼び出されますが、 mycomplex_2 型要素の場合にはオーバーライドする実手続き(myc2_plus_r もしくは r_plus_myc2)が呼び出されることになります。
9.2.5 抽象構造型 [5.1]
拡張可能構造型は ABSTRACT として宣言可能です。例:
TYPE, ABSTRACT :: mytype抽象型はインスタンス生成できません(すなわち抽象型の非多相変数を宣言すること は許されず、抽象型の多相変数はその型の非抽象拡張として割付けされなくてはなり ません)。
抽象型は DEFERRED 型結合手続きを含むことができます。
例:
... CONTAINS PROCEDURE(interface_name),DEFERRED :: tbpname無指定手続き結合においては結合(“=> name”)は許されず、 また示唆されることもありません。 interface_name は抽象引用仕様もしくは明示的な引用仕様を持つ手続き に対する名前でなくてはならず、それは無指定型結合手続き引用仕様を定義しま す。
抽象型を拡張する場合、通常結合のすべての無指定型結合手続きをオーバーライド するのでない限り、拡張型も抽象型である必要があります。
9.2.6 オブジェクト結合手続き [5.2]
これらは手続きポインタ成分であり、型結合手続きと似た動作をします。ただし 結合が型毎ではなくオブジェクト毎に行われる点が異なります。手続きポインタ 成分宣言の構文は次の通りです:PROCEDURE( [proc-interface] ) , proc-component-attr-spec-list :: proc-decl-list
ここで- それぞれのproc-component-attr-spec はNOPASS, PASS, PASS(arg-name), POINTER, PRIVATE, PUBLICのうちのいずれかで、
- それぞれのproc-decl は成分名にnullへのデフォルト初期化 (‘=> NULL()’、省略可)を続けたものです。
オブジェクト結合手続きは型結合手続きと同様に渡されたオブジェクトの仮引数 を持ちます。もしこれを望まないのであれば NOPASS 属性の指定が必要と なります(この指定は引用仕様が黙示的である場合(proc-interfaceが 指定されていない場合や型指定の場合)には必須です)。
次は引数無しのサブルーチンの並びを使用した例を示したものです。
TYPE action_list PROCEDURE(),NOPASS,POINTER :: action => NULL() TYPE(action_list),POINTER :: next END TYPE TYPE(t),TARGET :: top TYPE(t),POINTER :: p EXTERNAL sub1,sub2 top%action = sub1 ALLOCATE(top%next) top%next%action = sub2 ... p => top DO WHILE (ASSOCIATED(p)) IF (ASSOCIATED(p%action)) CALL p%action p => p%next END DO