[前へ] [目次へ] [次へ]

クラス


FGESではオブジェクトを作成できる型は全てクラスです。
これはクラスオブジェクト自体、メソッド、整数型なども例外ではありません。

クラスはグローバル定義空間には名前だけを宣言し、定義を後から行うことができます。
宣言だけ行われたクラスは不完全型として定義され、型名としてのみ使用可能になります。
不完全型のメンバを参照したりインスタンスを生成することはできません。
宣言のみされたクラスは同名のクラスを定義することでメンバの参照やインスタンスの生成が可能になります。

クラスは通常クラス、抽象クラス、ネイティブクラスに分けられます。
通常クラスはFGESで定義するクラスで、継承したりインスタンスを生成したりできます。
抽象クラスはFGESで定義する継承専用のクラスで、インスタンスを生成できません。
ネイティブクラスはC++レベルで定義されているクラスで、
インスタンスは生成できますが継承ができません。
これはC++レベルでインスタンスの扱いが異なることに起因しています。

上記の定義とは別に、ポータブルクラスという分類があります。
ポータブルクラスは主に「注入」を行うクラスに使用され、
ホストオブジェクトの型を限定せずに実行するためのクラスです。
ポータブルクラスは定義するクラスメンバメソッドが自動的に portable になることを除き、通常のクラスと同様です。

クラスの定義中、 SelfType を型名として使用すると定義中のクラス(所属クラス)を示すことができます。
これにより無名クラスでも自クラスを対象として扱えます。
ただし、これはコンパイル時に解決されるため、
継承などにより他のクラスから参照したとしても、 SelfType は定義時のクラスを示したままです。
クラスメンバメソッドを分割定義する場合、グローバル定義空間に記述するほうのメソッド宣言では
SelfType を使用できないことに注意してください。

抽象クラスの定義名の一文字目は $ 、ネイティブクラスの定義名の一文字目は * が付与されているため、
クラスの種類はクラスオブジェクトに対して GetName メソッドで定義名を取得し、その一文字目を調べることで確認できます。
クラスの定義名は「クラスを定義した時に使用した名前」をクラスオブジェクト自体に保存したもので、
クラスに別名を付けたり引数に渡すなど、参照のコピーを行っても変化しません。
また、ポータブルクラスは定義名に # が、抽象ポータブルクラスは定義名に $# が付与されます。

構文1:宣言のみを行う(定義は同じクラス名を持つ定義構文を使用します)
   class クラス名 ;

構文2:基底クラスを含む宣言のみを行う(定義は同じクラス名を持つ定義構文を使用します)
   この形式でクラスを宣言した場合、定義時に宣言した基底クラスを通常継承パスに含めなければいけません。
   class クラス名 extends 基底クラス名 ;

構文3:定義を行う(宣言がない場合は宣言を兼ねます)
   class 属性 クラス名 {
      定義内容
   }


構文4:継承や実装や注入を行うクラスの定義(宣言がない場合は宣言を兼ねます)
   
   class 属性 クラス名 : 継承指定 valuesインターフェイス指定 実装インターフェイス指定 注入クラス指定 {
      定義内容
   }


   属性に使用できるのは以下の組み合わせです。空欄にした場合は通常クラスを定義します。
記述意味
abstract抽象クラスを定義します。
portableポータブルクラスを定義します。

●継承指定

   定義するクラスに既存のクラスとの継承関係を設定します。
   FGESの継承には通常継承と内包継承があります。
   継承を行わない場合は省略できます。
   
●通常継承
   通常継承は言語定義メソッド( # で始まる名前のメソッド)を除くクラスメンバメソッド、
   クラス共有変数、クラスメンバ変数、実装インターフェイス、注入クラスを新しく定義するクラス(派生クラス)に継承します。
   ただし、クラスメンバメソッドおよびクラス共有変数は名前空間を共有しているだけで、
   オブジェクトが複製されるわけではありません。
   派生クラス側で基底クラスのクラス共有変数を変更した場合、
   変更されるのは基底クラスのクラス共有変数です。
   
   また、実装インターフェイスは派生クラス側で同じインターフェイスの実装宣言を行った場合、
   基底クラス側の同インターフェイス定義は当該派生クラスからは参照されなくなります。
   この動作はメソッドのオーバーライドとよく似ていますが、
   super で基底クラス側のインターフェイス実装を示すことはできません。
   
   通常継承の基底クラスになれるのは通常クラス、抽象クラスだけです。
   ネイティブクラス、インターフェイスは通常継承の対象にできません。
   
   通常継承したクラスは基底クラスへ暗黙にキャストすることができます。
   基底クラスにキャストしている派生クラスを元に戻すには明示的なキャストが必要です。
   
   構文:(基底クラス名は 型名 解釈です)
   extends アクセス属性 基底クラス名

   アクセス属性に使用できるのは以下のいずれかです。省略した場合は public として扱います。
記述意味
public継承されるメンバのアクセス属性は基底クラスのまま変わりません。
readable継承されるメンバのうち、publicアクセス属性のものはreadableアクセス属性に変更されます。
internal継承されるメンバのうち、public/readableアクセス属性のものはinternalアクセス属性に変更されます。
native継承されるメンバは全てnativeアクセス属性に変更されます。
   
●内包継承
   内包継承すると継承元のクラスがインスタンス変数 wraps として定義され、
   定義したクラス(以降 内包クラス)の定義空間に要求された名前やインターフェイスがない場合、
   内包継承したインスタンスにその要求をリダイレクトします。
   この動作により、あたかも内包継承したクラスを内包クラスが継承しているように見えます。
   また、一部を除きネイティブインターフェイスもこのリダイレクトの対象となるため、
   通常クラスでありながらネイティブインターフェイスを使えるクラスを
   制限付きながら作成することが可能となります。
   
   内包継承したクラスと内包クラスの間には通常の継承関係が設定されるわけではありません。
   内包継承したクラスが持つメンバと同名のメソッドや変数を内包クラスで定義することができますが、
   これによって内包継承したクラスの動作に影響を与えることはありません。
   また、内包継承したクラスへ内包クラスをキャストすることも、逆にキャストすることもできません。
   ただし、内包継承したクラスが実装しているインターフェイスについては、
   自動的にリダイレクト宣言とリダイレクトメソッド定義が行われるため、暗黙的にキャストすることができます。
   また、ここで定義されるリダイレクトメソッドは上書き可能です。
   これにより内包継承したクラスのインターフェイス実装の一部だけを上書きすることができます。
   ただしC++レベルのインターフェイス関数はこの方法で上書きすることはできません。
   ネイティブインターフェイスを要求するネイティブメソッドに対しては、
   リダイレクトメソッドの上書きは意味を持たない可能性があります。
   
   内包クラスで静的名前解決を行った時に、内包継承したクラスへのリダイレクトが行われた場合、
   FGESコンパイラはリダイレクトを行うコードを直接生成します。
   これは内包クラスを継承したクラスで内包継承したクラスへのリダイレクトを
   抑止できない場合が存在することを意味し、オーバーライドに失敗したように見えます。
   (これはC++で非仮想関数をオーバーライドした場合とほぼ同じ動作となります)
   これはリダイレクトを行った場合にのみ発生するので、
   派生クラスでオーバーライドする可能性のある内包継承したクラスのメソッドは
   内包クラスで再定義し、明示的にリダイレクトメソッドを記述することで回避できます。
   
   内包継承の対象クラスになれるのは通常クラス、ネイティブクラスだけです。
   抽象クラス、実体化不可クラス、インターフェイスは内包継承の対象にできません。
   
   構文:(対象クラス名は 型名 解釈です)
   wraps アクセス属性 対象クラス名

   アクセス属性はインスタンス変数 wraps のアクセス属性として使用されます。
   要求のリダイレクト時にもアクセス属性が確認されますが、
   ネイティブインターフェイスのネイティブメソッドからのリダイレクトは関係なく実行されます。
   これはネイティブメソッドからの呼び出しが native アクセス権限で行われることによります。
   アクセス属性に使用できるのは以下のいずれかです。省略した場合は public として扱います。
記述意味
publicwrapsおよびリダイレクトはどこからでも使用できます。
readablewrapsおよびリダイレクトは内包クラスおよびその派生クラス、注入クラスからはフルアクセス、
それ以外からは読み取り専用として使用できます。
internalwrapsおよびリダイレクトは内包クラスおよびその派生クラス、注入クラスからのみ使用できます。
nativewrapsおよびリダイレクトはFGESレベルでは一切使用できません。
ただしネイティブインターフェイスは使用できる場合があります。


●valuesインターフェイス指定

   values インターフェイスは、引数リストで values を宣言した際に使用するインターフェイスです。
   values インターフェイスを宣言していないクラスは引数リストで values による擬似値渡しが使用できません。
   values インターフェイス宣言は対象のインターフェイスの実装宣言を兼ね、
   言語定義メソッド #Value を合わせて定義する必要があります。
   ( #Value は戻り値なし、引数として values インターフェイス型をひとつ取ります)

   また、 values インターフェイスは継承すると、基底クラスで implements で実装宣言したインターフェイスとして継承されます。
   継承したクラスでも values インターフェイスとして扱うには改めて values インターフェイス指定と実装が必要です。

   この項目は values インターフェイスを使用しない場合は省略できます。

   構文:( values インターフェイス名は 型名 解釈です)
   values valuesインターフェイス名

   例:
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
   class C:values IInteger{
      
var int n;
      
method #Value(IInteger v){@n=v;}//valuesインターフェイスから変換するためのメソッド
   }
   
method C Def(values C v){//実際の仮引数型はIInteger
      
retval v.n+10;//retvalでもvaluesインターフェイスを使用できます
   }
   
method void Use(){
      Def(100).n;
//評価結果は110
   } 

●実装インターフェイス指定

   定義するクラスが実装するインターフェイスを宣言します。
   実装するインターフェイスの数に上限はありませんが、
   数が増えるとインターフェイス呼び出しの解決処理が重くなります。
   
   実装必須インターフェイスとして宣言した場合、
   定義するクラスの派生クラスは抽象クラスであるか、または実装必須インターフェイスを実装宣言しなければいけません。
   また、実装必須インターフェイスは抽象クラスでしか宣言できず、
   その派生クラスも抽象クラスである場合は実装必須インターフェイスのまま継承されます。
   
   実装必須インターフェイスの宣言は扱い上は実装宣言もしていることになり、
   当該インターフェイス型へキャストしたり、インターフェイスメソッドを定義することができます。
   ただし、定義したインターフェイスメソッドはそのままでは参照されず、
   派生クラスで alias によって割り当てられなければ使用されません。
   これは派生クラスで実装宣言することを強制することから、派生クラス側の定義が使用されるためです。
   
   implements でインターフェイスの実装を宣言した場合、
   定義中のクラスが抽象クラスであってもその完全な実装を行う必要があります。
   そのようなインターフェイスが必要だが、実装を行うことができない場合は実装必須インターフェイスとして宣言します。
   
   この項目はインターフェイスを実装したり、実装必須インターフェイスを宣言しない場合は省略できます。

   構文1:(実装インターフェイス名は 型名 解釈です)
   implements 実装インターフェイス名

   構文2:複数を一斉に実装する(実装インターフェイス名は 型名 解釈です)
   implements 実装インターフェイス名1 , 実装インターフェイス名2 , 実装インターフェイス名3

   構文3:実装必須インターフェイスを宣言(実装必須インターフェイス名は 型名 解釈です)
   required 実装必須インターフェイス名

   構文4:実装必須インターフェイスを複数一斉に宣言する(実装必須インターフェイス名は 型名 解釈です)
   required 実装必須インターフェイス名1 , 実装必須インターフェイス名2 , 実装必須インターフェイス名3

   これらの構文は順不同に連続して複数回使用できます。
   例:
<  1>
<  2>
   class abstract C:implements IInteger required IFloat implements IString,IBool{
   } 

●注入クラス指定

   定義するクラスに注入するクラス(注入クラス)を指定します。
   クラスを注入すると、注入クラスに定義されている内容を定義するクラスに複製します。
   注入できるクラスは通常クラス、抽象クラスのみで、ネイティブクラスは対象外です。
   ただし、注入クラスが内包継承を行っている場合、
   定義するクラスと注入クラスがともに同一のクラスを内包継承していなければ注入することができません。
   
   ここで複製されるのはインスタンス変数、クラス共有変数(言語定義メソッドを含む)、
   宣言している全てのインターフェイス、注入クラスに注入されている注入クラスです。
   注入クラスが通常継承を行っている場合、基底クラス由来の内容も複製されます。
   この時、注入クラスから見えていない基底クラス由来の内容は対象外です。
   また、この複製は参照の複製によって行われ、クラス共有変数は同じオブジェクトを共有します。
   さらに、注入クラスは定義するクラスに対する internal アクセス権限を獲得します。
   この時、注入クラスの基底クラスや、注入クラスに注入されている注入クラスも同時に権限を獲得します。

   注入を行う時、名前衝突が発生した場合はエラーになります。
   ただし、同一の宣言(クラス共有変数は型と参照が完全に同一、インスタンス変数は同一クラス由来の宣言)は
   エラーにならず、無視されます。
   また、名前衝突したクラス共有変数が両方ともメソッドであった場合で、
   直接的なオーバーライド関係(どちらか一方がもう片方をオーバーライドしている、
      またはオーバーライドしているメソッドを遡ることでもう片方に到達できる)を持つ場合、
   オーバーライドしている方が残るように処理されます(注入オーバーライド)。
   つまり、定義するクラス側に現存するメソッドが注入クラスのメソッドをオーバーライドしたものである場合、
   何も起こらず、定義するクラス側に現存するメソッドがそのまま残されます。
   注入クラスのメソッドが定義するクラス側に現存するメソッドをオーバーライドしたものである場合、
   注入クラスのメソッドで定義するクラスのメソッドは置き換えられ、オーバーライドした扱いになります。
   この時、定義するクラスに元々あったメソッドは参照が解除されるだけで、消滅することはありません。
   
   インターフェイスの実装宣言は定義中のクラスを含め最初に行ったクラスのものが使用されます。
   注入によってインターフェイスの実装宣言が複製された場合、その実装も複製されます。
   既に実装宣言されているインターフェイスが注入によって再宣言された場合は無視されます。
   複数のクラスを一斉に注入する場合、リストの左から順に注入が行われます。
   注入するクラスに同じインターフェイスを実装宣言するクラスが複数ある場合、より左側のクラスが優先されます。
   
   実装必須インターフェイスは宣言のみが複製され、実装は複製されません。
   既に宣言されている実装必須インターフェイスが注入によって再宣言されてもエラーになりません。
   
   注入は挙動的には Mix-in や Trait に近いものですが、
   継承パスに合成されるわけではなく、あくまで該当クラス上で定義している扱いとなります。
   
   定義するクラスと注入クラスの間には通常の継承関係が設定されるわけではありません。
   そのため、注入クラスのメソッドを 
   定義するクラスのインスタンスをホストとして 呼び出した場合例外が発生する場合があります。
   これを避けるためには、注入クラスのメソッドを portable 属性でコンパイルします。

   注入クラスから注入されたメソッドは所属クラスが異なるため、定義を上書きすることができます。
   また、クラス共有変数を用いてメソッドを取り込んだ場合と異なり、オーバーライド対象にすることができます。
   通常クラスに抽象クラスを注入した場合、 required な項目はクラスの定義中に上書きしなければいけません。
   
   注入クラスから注入したメソッド内で super を使用した場合、
   その対象は注入クラスの基底クラスを指したままです。
   定義するクラスの基底クラスに読み替えられることはありません。

   注入は概念的にはクラスの直系の継承パスに対する傍流の継承パスを作成しますが、
   名前空間は共有し、同一の宣言が合成されるため仮想継承のような挙動になります。
   無計画な注入はクラスの論理構造を複雑化し、バグの原因になります。
   注入を行う時は論理構造の変化に注意してください。
   
   この項目は注入を行わない場合は省略できます。
   
   構文1:(注入クラス名は 型名 解釈です)
   inject 注入クラス名

   構文2:複数を一斉に注入する(注入クラス名は 型名 解釈です)
   inject 注入クラス名1 , 注入クラス名2 , 注入クラス名3

   例:
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
< 11>
< 12>
< 13>
< 14>
< 15>
< 16>
< 17>
< 18>
< 19>
< 20>
< 21>
< 22>
< 23>
< 24>
< 25>
< 26>
< 27>
< 28>
< 29>
< 30>
   class X{
      
classvar int x_cv=10;
      
var int x_v;
      
method portable int x_met(){
         
//この例でthisはAやBのインスタンスなので、portableでなければ呼び出せない
         
         //↓X::x_vにアクセスしているように見えるが、あくまでthis.$x_vへのアクセス。
         //↓ただし@$x_vとは違い、X::x_vの型であるint型として解釈できるか実行時に検証され、
         //↓解釈できなければ例外となる。さらにコンパイル中、@x_vはint型として解決される。
         
retval @x_v*2;
      }
   }
   
class A:inject X{
   }
   
class B:extends A{
      
method override int x_met(){
         
retval super()*3;//superの対象はA::x_met (Aに注入された X::x_met)
      }
   }
   
method void Use(){
      A a;
      a.x_v=100;
//A::x_v (Aに注入された X::x_v)を操作する
      (A::x_cv#==X::x_cv);//true
      
a.x_met();//A::x_met (Aに注入された X::x_met)を呼び出す→結果は200
      
      
B b;
      b.x_v=50;
      (a.x_v#==b.x_v);
//false
      
b.x_met();//300
   } 

●定義内容

   「定義内容」の部分はクラス定義空間として扱われます。
   クラス定義空間に定義できる内容は以下の通りです。
   

●デフォルトアクセス属性の変更

   このクラス定義空間で定義するインスタンス変数、クラス共有変数、クラスメンバメソッドの
   デフォルトのアクセス属性を変更します。一度も設定していない場合のデフォルトは public です。
   アクセス属性に使用できるのは以下のいずれかです。
   クラスメンバメソッドの場合、呼び出しにメソッドオブジェクト自体を変更する必要がないため、
   readable 属性でも public と同様に呼び出すことができます。
記述意味
public:対象はどこからでも使用できます。
readable:対象は同クラスおよびその派生クラス、注入クラスからはフルアクセス、
それ以外からは読み取り専用として使用できます。
internal:対象は同クラスおよびその派生クラス、注入クラスからのみ使用できます。
native:対象はFGESレベルでは一切使用できません。

   例:
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
< 11>
   class C{
      
var int def_attr;//デフォルト(public)
   
public:
      
var int public_attr;//public
   
readable:
      
var int readable_attr;//readable
   
internal:
      
var int internal_attr;//internal
   
native:
      
var int native_attr;//native
   } 
   

●インスタンス変数の定義

   変数定義の構文については 変数 の項目を参照してください。

   インスタンス変数はインスタンス(クラスを実体化したオブジェクト)ごとに個別に保持される変数です。
   
   実体定義をした場合、クラスのインスタンスが作成されるタイミングで実体化され、
   生成したクラスのイニシャライザが実行されます。
   そのため、実体定義をする場合は変数の型が
   不完全型、抽象クラス、インターフェイス、実体化不可型であってはいけません。
   
   インスタンス変数はクラスメンバ名前空間に登録され、
   クラスメンバメソッドからはメンバ参照演算子 @ を使用してアクセスできます。
   また、アクセス属性上でアクセス可能であれば、
   インスタンスに対してメンバ参照演算子 . を使用してアクセスできます。
   
   インスタンス変数として実体化されたオブジェクトは
   インスタンスの従属解放オブジェクトとして扱われ、
   インスタンスが消滅するのに連動して消滅します。
   

●クラス共有変数の定義

   変数定義の構文については 変数 の項目を参照してください。

   クラス共有変数はクラスオブジェクト自体に一つだけ保持される変数です。
   クラス共有変数はC++の静的メンバ変数と概ね同等です。
   
   実体定義をした場合、クラス共有変数はコンパイル中に直ちに実体化され、
   生成したクラスのイニシャライザが実行されます。
   そのため、実体定義をする場合は変数の型が
   不完全型、抽象クラス、インターフェイス、実体化不可型であってはいけません。
   
   また、初期化式が付随している場合、初期化式も直ちに実行されます。
   ここで実行されるイニシャライザおよび初期化式はコンパイルスレッドで実行され、
   一定時間以内に完了しない場合や、他のスレッドを待機するようなコードを実行すると
   例外が投入されます。(コンパイル中実行の制限)
   
   クラス共有変数として実体化されたオブジェクトは定義中のクラスと同じ
   メモリ管理オブジェクトに接続されます。(通常、クラスはグローバルメモリーホストに接続されます)
   グローバルメモリーホストはVMの実行中永続するメモリ管理オブジェクトであるため、
   クラス共有変数は通常解放されず、VM終了時にもクリアラーは呼び出されません。
   (ただし、VM終了時にC++レベルのデストラクタは呼び出されます)

   クラス共有変数はクラスメンバ名前空間に登録され、
   メンバメソッドからはメンバ参照演算子 @ を使用してアクセスできます。
   また、アクセス属性上でアクセス可能であれば、
   クラスオブジェクトに対してクラスメンバ参照演算子 :: を使用してアクセスできます。
   インスタンスに対してメンバ参照演算子 . を使用してもアクセスできます。
   

●クラスメンバメソッドの定義

   メソッド定義の構文については メソッド の項目を参照してください。

   クラス定義空間に定義されたメソッドはクラスメンバメソッドと呼びます。
   クラスメンバメソッドのうち、 static 属性を持つメソッドを特にクラスメソッド、
   インターフェイスの実装に使用するメソッドを特にインターフェイスメソッドと呼びます。
   
   インターフェイスメソッドを定義する場合はインターフェイス名も含めて宣言する必要があり、
   同名であってもインターフェイスが異なる場合は別のメソッドとして扱われます。
   また、インターフェイスメソッドは要求権限がより少ないメソッド
   ( static 属性のメソッド、非 const インターフェイスメソッドに対して const 属性のメソッド)を適用することができます。

   この方法で定義したメソッドは定義中のクラスに所属するメソッドになります。
   定義中のクラス定義空間に異なるクラスに所属するメソッドを配置した場合、
   同じ外部インターフェイスを持つメソッド定義を行うことで定義を上書きすることができます。
   この時、もともとあったメソッドオブジェクトには変更は加えられず、参照だけが切り離されます。
   その上で、参照は新たに定義、作成されるメソッドオブジェクトを指す様に変更されます。
   
   定義を上書きできるのは定義中のクラスに直接定義または注入されたメソッドだけです。
   基底クラス由来の項目に対しては定義の上書きは行われません。
   
   クラス定義中に言語定義メソッド #Setup (戻り値/引数ともになし)を定義した場合、クラス定義の完了時に実行されます。
   このメソッドはコンパイルスレッドで実行され、一定時間以内に完了しない場合や、他のスレッドを待機するようなコードを実行すると
   例外が投入されます。(コンパイル中実行の制限)
   また、実行タイミングの都合上、このメソッドを分割定義することはできません。

   メソッドが宣言または定義されると、 FGESMethod 型の同名のクラス共有変数として定義されます。

●エイリアス(別名)の定義

   クラスメンバ名前空間に既にある参照を複製します。
   複製した参照と元になった参照は同じオブジェクトを共有し、
   オブジェクトに対して行われた結果も共有されます。
   
   また、この定義によって参照に関連付けられているオブジェクトの
   メモリ管理オブジェクトが変更されることはありません。
   
   複製元に使用できるのは定義中のクラス、およびその基底クラスの
   クラス共有変数、クラスメソッド、クラスメンバメソッド、インターフェイスメソッドのみです。
   インスタンス変数や継承関係のないクラスのメンバは対象にできません。
   
   構文:
   alias 複製元の名前 作成する名前 ;

   複製元の名前はクラス名の後に :: を付け、
   クラス内クラスを示す場合は :: でクラスパスを示すことができます。
   クラス名が空欄の場合は定義中のクラスを意味し、
   super をクラス名とした場合は基底クラスを意味します。

   複製元の名前、作成する名前ともにインターフェイス名は識別名の後に @@ を付け、
   クラス内インターフェイスを示す場合は @@ でクラスパスを示すことができます。
   インターフェイス名が空欄の場合はクラスメンバメソッドを意味し、
   指定した場合はインターフェイスメソッドを意味します。
   
   例:実装必須インターフェイスの実装用テンプレートを提供し使用する
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
< 11>
< 12>
   class abstract base_class:required IInteger{
      
var int n;
      
method void IInteger@@Set(IInteger v){@n=v;}//実装用テンプレート
   }
   
class deriv_class:extends base_class implements IInteger{
      
alias super::IInteger@@Set IInteger@@Set;//テンプレートを実装として割り当てる
   }
   
method void Use(){
      deriv_class o;
      o
#TypeCast IInteger.Set(100);//deriv_class::IInteger@@Setの呼び出し
      
o.n;//評価結果は100
   } 
   

●クラス内クラスの定義

   クラス定義空間に定義する場合、不完全型としてクラスを宣言することはできません。

   クラスが定義されると、 FGESClass 型の同名のクラス共有変数として定義されます。
   現在、型名としてクラス内クラスを参照する場合、アクセス属性は無視されます。

●クラス内インターフェイスの定義

   インターフェイス定義の構文については インターフェイス の項目を参照してください。

   クラス定義空間に定義する場合、不完全型としてインターフェイスを宣言することはできません。

   インターフェイスが定義されると、 FGESInterface 型の同名のクラス共有変数として定義されます。
   現在、型名としてクラス内インターフェイスを参照する場合、アクセス属性は無視されます。


[前へ] [目次へ] [次へ]

最終更新 2018/03/06