- 手軽なスクリプト言語としてのF#
- 手軽なスクリプト言語としてのF# その2
- 手軽なスクリプト言語としてのF# その3
- 手軽なスクリプト言語としてのF# その4
- 手軽なスクリプト言語としてのF# その5
- 手軽なスクリプト言語としてのF# その6
- 手軽なスクリプト言語としてのF# その7
- 手軽なスクリプト言語としてのF# その8「レコード」
- 手軽なスクリプト言語としてのF# その9「クラス」
さて、記念すべき10回目のエントリです。やっと継承できるようになりました。因みに、この一連のエントリのタイトルでスクリプト言語として〜と書いてますが、このエントリのサンプルを作るときはばっちりコンパイルしてるので若干矛盾してなくもない今日この頃です。まぁ気にせずいってみます。
アブストラクトなクラス
クラスを継承する際のベースクラスは別にアブストラクトなクラスじゃなくてもいいのですが、ついでなのでアブストラクトなクラスにしてみようと思います。アブストラクトなクラスの定義は以下のようになります。
// アブストラクトなクラスの定義 [<AbstractClass>] type Animal(name) = let name = name member this.Name with get() = name // 引数を受け取らないで何も戻り値がない仮想メソッドCryの定義 abstract Cry : unit -> unit // Cryのデフォルト実装を提供出来る default this.Cry() = printfn "%s > ...." this.Name
ちょっと変わってるのがAbstractClass属性を指定してやることでアブストラクトなクラスになるという点です。アブストラクトなメンバーは、memberの代わりにabstractを使って定義します。上の例では引数無し、戻り値無しのCryというメソッドが、それにあたります。因みにmemberのかわりにabstractを使うというのは、ちょっと嘘で本当はabstract memberと書くところをmemberを省略できるというだけです。実用上はmemberの代わりにabstractを使うと覚えてても差し支えは無いと思います。
もちろんabstract Hoge : string with getこのような形でアブストラクトなプロパティも定義出来ます。(ここでは使ってません)
継承の仕方
継承は、inheritキーワードを使用して記述します。大体以下のようになります。
type クラス名(引数) = inherit 基本クラス名(引数) override this.プロパティ名 = 値 override this.メソッド名(引数) = メソッドの中身
上記の例ではoverrideの仕方しか書いてませんが、ふつうにメソッドやプロパティを派生クラスで定義することも出来ます。とりあえず、Animalクラスを継承してDogクラスを定義してみました。犬はワンワンと鳴きます。
// 独自の鳴き声を持つクラス1 type Dog(name) = inherit Animal(name) override this.Cry() = printfn "%s > ワンワン" this.Name
ポリモフィズムしてみよう
ということで、オブジェクト指向の例題とかで使われるけど、オブジェクト指向のメリットは全然理解できずにポリモフィズムの挙動はばっちり理解できる動物と犬や猫といった例を使ったプログラムと実行結果を示して、この回を締めくくろうと思います。
// アブストラクトなクラスの定義 [<AbstractClass>] type Animal(name) = let name = name member this.Name with get() = name // 引数を受け取らないで何も戻り値がない仮想メソッドCryの定義 abstract Cry : unit -> unit // Cryのデフォルト実装を提供出来る default this.Cry() = printfn "%s > ...." this.Name // アニマルのデフォルト実装を使うクラス type Ferret(name) = inherit Animal(name) // 独自の鳴き声を持つクラス1 type Dog(name) = inherit Animal(name) override this.Cry() = printfn "%s > ワンワン" this.Name // 独自の鳴き声を持つクラス2 type Shibayan() = inherit Animal("shibayan") override this.Cry() = printfn "%s > メイド ニーソ" this.Name // 独自の鳴き声を持つクラス3 type 割と普通() = inherit Animal("割と普通") override this.Cry() = printfn "%s > エロース エロース(深夜の鳴き声" this.Name // 動物のリストを定義 let animals : Animal list = [ Dog("ポチ"); Shibayan(); Ferret("ふぇれっと"); 割と普通() ] // 皆に鳴いて貰う for animal in animals do animal.Cry()
実行すると以下のようになります。
ポチ > ワンワン shibayan > メイド ニーソ ふぇれっと > .... 割と普通 > エロース エロース(深夜の鳴き声
ちゃんとベースクラスの型で受けて、メソッドの呼び出し結果は派生クラスになるというポリモフィズムの動きが確認できると思います。今日は以上です。