1Kuinのクラス
Kuinでは、クラスを図1-1のように定義します。
class 名前()
メンバ定義
end class
class 名前(継承元クラス名)
メンバ定義
end class
括弧内にクラス名を書くと、そのクラスを継承したクラスになります。 省略すると「kuin@Class」を継承します。 従って、すべてのクラスは継承元を辿ると最終的に「kuin@Class」を継承していることになります。
メンバ定義には、alias文、const文、var文、classブロック、enumブロック、funcブロックが書けます。
このうち、var文はクラスのプロパティ(メンバ変数)となり、funcブロックはメソッド(メンバ関数)となります。 それ以外はクラス内でのみ参照できる定義となります。
クラスの仕様は図1-2の通りです。
- クラスを継承すると、継承元クラスのメンバがすべて引き継がれる。 継承元クラスが継承していた場合、継承元を辿ってメンバがすべて引き継がれる。
- メンバのうちプロパティとメソッドに限って、定義の先頭に「+」を付けることで「パブリックメンバ」となりクラス外部に公開される。 パブリックメンバ以外はクラス外部から参照できない。
- メソッド内では、自身のインスタンスが「me」という変数で参照できる。
2継承
メソッドは、定義の先頭に「*」を付けることで、継承元クラスの同名メソッドを継承して上書きできます。
継承の仕様は図2-1の通りです。
- 継承したメソッドは継承元のメソッドと、「+」の有無や、引数の型および名前や、戻り値の定義が一致していなければならない。
- 「+」と「*」を両方指定するときは、「+*」の順序で記述する。
- 継承元クラスに存在しないメソッドを継承しようとしたときや、継承元クラスに存在するメソッドと同名のメソッドを継承なしに定義した場合はコンパイルエラーとなる。
継承先メソッド内から継承元メソッドを呼び出すには「super」を使います。 superは継承先メソッド内でのみ参照できる関数で、第1引数にはmeを渡して呼び出します(図2-2)。
- func main()
- class Parent()
- +func f(n: int): int
- ret n * n
- end func
- end class
-
- class Child(Parent)
- +*func f(n: int): int
- ret super(me, n) + n
- end func
- end class
-
- var child: Child :: #Child
- do cui@print(child.f(3).toStr() ~ "\n")
- end func
このプログラムを実行すると、Parentクラスのfメソッドが呼び出されて「3*3=9」が計算されたのちに、Childクラスのfメソッド内で「9+3=12」が計算され、「12」が表示されます。
3ctorとcmp
kuin@Classに定義されているメソッドのうち、「ctor」「cmp」は継承可能です。
3.1ctor
ctorメソッドを継承すると、コンストラクタ(インスタンス生成時の初期化処理)が実装できます。 ctorメソッドの定義は図3-1の通りです。
func ctor()
ctorメソッドを継承しない場合、何も処理をしない空のメソッドになります。 ctorメソッドの実装例は図3-2の通りです。
- func main()
- class Test()
- +var a: int
- *func ctor()
- do me.a :: 5
- end func
- end class
-
- var test: Test :: #Test
- do cui@print(test.a.toStr() ~ "\n")
- end func
このプログラムを実行すると、「#Test」の段階でTestクラスのctorメソッドが呼ばれ、最終的に画面には「5」が表示されます。
3.2cmp
cmpメソッドを継承すると、クラスの比較処理が実装できます。 cmpメソッドの定義は図3-3の通りです。
+func cmp(t: kuin@Class): int
t|比較対象の値
戻り値|比較対象の値よりも大きければ正、小さければ負、等しければ0を返す
cmpメソッドを継承しない場合、比較時に例外(0xE9170004)が発生し、比較できないクラスとなります。 cmpメソッドの使用例は図3-4の通りです。
- func main()
- class Test()
- +var a: int
- +var b: int
- +*func cmp(t: kuin@Class): int
- var t2: Test :: t $ Test
- if(me.a + me.b > t2.a + t2.b)
- ret 1
- elif(me.a + me.b < t2.a + t2.b)
- ret - 1
- else
- ret 0
- end if
- end func
- end class
-
- var test1: Test :: #Test
- do test1.a :: 2
- do test1.b :: 3
- var test2: Test :: #Test
- do test2.a :: 4
- do test2.b :: 5
-
- do cui@print((test1 >= test2).toStr() ~ "\n")
- end func
この例ではTestクラスの比較方法を、aとbの和で定めています。
4クラスのキャスト
クラスのインスタンスは、そのクラスとその継承元クラスの型にのみ変換できます(図4-1)。
- func main()
- class Parent()
- end class
-
- class Child(Parent)
- end class
-
- var parent: Parent :: #Child
- end func
ただし継承先クラスに変換する場合には、「$」演算子によって明示的にキャストしないとコンパイルエラーになります。 このときインスタンスが、そのインスタンスのクラスおよび継承元クラスの型に変換される場合には変換できますが、継承先クラスに変換される場合には例外(0xE9170001)が発生します(図4-2)。
- func main()
- class Parent()
- end class
-
- class Child(Parent)
- end class
-
- var parent: Parent
-
- do parent :: #Child
- var child1: Child :: parent $ Child {キャスト成功}
-
- do parent :: #Parent
- var child2: Child :: parent $ Child {キャスト失敗}
- end func
キャストに成功するかどうかは「=$」もしくは「<>$」演算子で判断できます。