継承によるメソッドの置き換え
次に継承によるメソッドの置き換えについてC#と比較してみましょう。
C#では、子クラスにて親クラスにあるメソッドと同じ名前のメソッドを作成し置き換えるには、newキーワードを使用します。しかし、newキーワードを使用した子クラスのメソッドは親クラス型オブジェクト経由で呼び出された場合には置き換えられず、親クラスのメソッドを呼んでしまいます。これを強制的に子クラスのメソッドに置き換えるためには、C#では、”virtual”と”override”キーワードを使用します。以下の例では、testMethod1はnewで置き換えられているため、親クラス型のオブジェクト(a)経由で呼び出された場合、置き換えられず、親クラスのメソッドを呼びますが、testMethod2は強制的に子クラスで実装されたメソッドに置き換えられます。
class testBaseClass1 //親クラス { public void testMethod1() { Console.WriteLine("ベース機能"); } public virtual void testMethod2() { Console.WriteLine("ベース機能バーチャル"); } } class testChildClass1 : testBaseClass1 //testBaseClass1を継承 { public new void testMethod1() { Console.WriteLine("子機能new"); } // virtual + overrideキーワードでtestMethod2のみ完全に置き換えらる public override void testMethod2() { Console.WriteLine("子機能override"); } } class Test { static void Main() { testBaseClass1 a = new testChildClass1(); testChildClass1 b = new testChildClass1(); //親クラスオブジェクトへの参照経由で呼び出すと置き換えられていない。 a.testMethod1(); b.testMethod1(); //親オブジェクトへの参照経由で呼び出しても、置き換えられている。 a.testMethod2(); b.testMethod2(); } }
▼
ベース機能 子機能new 子機能override 子機能override
同様のテストをF#でしてみましょう。testBaseClass1とそれを継承しているtestChildClass1は2つの同名のメソッドを持ちますが、メソッドの上書きの強制度が異なります。testMethod1を親クラスのオブジェクト(testObj1)経由で呼び出す場合には、親クラスで実装されたメソッドが呼ばれますが、”abstract member”と”override”キーワードで定義されたtestMethod2は子クラスで実装されたメソッドが置き換えられて呼び出されます。”abstract member“で宣言されたメンバーは抽象メンバーですが、”default”とセットで使用し親クラスにてデフォルトの実装を定義することで、他.NET言語のvirtualのように機能します。
open System type testBaseClass1() = //親クラス member this.testMethod1() = Console.WriteLine("testBaseClass1のtestMethod1") abstract member testMethod2 : unit -> unit //抽象メソッド default this.testMethod2() = //抽象メソッドのデフォルト実装 Console.WriteLine("testBaseClass1のtestMethod2") type testChildClass1() = inherit testBaseClass1() //testBaseClass1を継承 member public this.testMethod1() = Console.WriteLine("testChildClass1のtestMethod1") // "abstract member " + "override "がdefault実装を強制的に置き換える override this.testMethod2() = Console.WriteLine("testChildClass1のtestMethod2") let mutable testObj1 = new testBaseClass1() //mutableで可変オブジェクト let testObj2 = new testChildClass1() testObj1 <- testObj2;; testObj1.testMethod1();;//親クラス型への参照経由でもメソッドは置き換えられないはず testObj2.testMethod1();; testObj1.testMethod2();;//親クラス型への参照経由でもメソッドは置き換えられているはず testObj2.testMethod2();;
▼
testBaseClass1のtestMethod1 val it : unit = () > testChildClass1のtestMethod1 val it : unit = () > testChildClass1のtestMethod2 val it : unit = () > testChildClass1のtestMethod2 val it : unit = ()