親クラスのメソッドをサブクラスで上書きしたらどうなるか。
どうなるか@Java
public class Override { public static void main(String[] args) { MyTest mt = new YourTest(); mt.hello(); } } class Test { public void hello() { System.out.println("Test#hello()"); } } class MyTest extends Test { public void hello() { System.out.println("MyTest#hello"); } } class YourTest extends MyTest { public void hello() { System.out.println("YourTest#hello"); } }
実行した結果は、
YourTest#hello
となります。
この短いコードだとあんまり実感ないですが、素直に見ればMyTest#helloを呼んでいる(ように見える)のに、実際はYourTest#helloが呼ばれます。
じゃあ、C#で同じようなことをやるとどうなるかというと、
using System; namespace test { class Override { static void Main() { MyTest mt = new YourTest(); mt.hello(); } } class Test { public void hello() { Console.WriteLine("Test#hello"); } } class MyTest : Test { public void hello() { Console.WriteLine("MyTest#hello"); } } class YourTest : MyTest { public void hello() { Console.WriteLine("YourTest#hello"); } } }
コンパイル時にワーニングが出ます。
>csc Override.cs Microsoft (R) Visual C# 2008 Compiler version 3.5.21022.8 for Microsoft (R) .NET Framework version 3.5 Copyright (C) Microsoft Corporation. All rights reserved. Override.cs(24,15): warning CS0108: test.MyTest.hello()' は継承メンバ 'test.Test.hello()' を隠します。意図的に隠す場合はキーワード new を使用してください。 Override.cs(16,15): (以前のエラーに関連する警告の位置) Override.cs(32,15): warning CS0108: test.YourTest.hello()' は継承メンバ 'test.MyTest.hello()' を隠します。意図的に隠す場合はキーワード new を使用してください。 Override.cs(24,15): (以前のエラーに関連する警告の位置)
要は勝手に上書きすんなってことですね。これは親切な気がします。さっきのJavaで示した例のような誤解を招くコードは防げますね。(実際やるかどうかは別として。)
ちなみに、上のメッセージに出ているように、キーワードnewを付加すれば、上書きすることが出来ます。
キーワードnewを付けても付けなくても、この結果はこうなります。
MyTest#hello
コード通り、MyTest#helloが呼ばれてしまいました。。
C#もC++と同じく、仮想関数定義にしないとポリモーフィズムにならないようです。
ので、こんなvirtualキーワードを付け加えてこうします。
using System; namespace test { class Override { static void Main() { MyTest mt = new YourTest(); mt.hello(); } } class Test { public virtual void hello() { Console.WriteLine("Test#hello"); } } class MyTest : Test { public override void hello() { Console.WriteLine("MyTest#hello"); } } class YourTest : MyTest { public override void hello() { Console.WriteLine("YourTest#hello"); } } }
この結果はこうです。
YourTest#hello
今度はちゃんとポリモーフィズムしてくれました。このソースは最初のJavaソースと同じ動きになりますね。
ちなみに、YourTest#helloをoverrideキーワードの代わりにnewキーワードとすることも出来ます。
例えばこんな感じ。
using System; namespace test { class Override { static void Main() { YourTest yt = new YourTest(); yt.hello(); Test test_yt = yt; test_yt.hello(); MyTest mytest_yt = yt; mytest_yt.hello(); } } class Test { public virtual void hello() { Console.WriteLine("Test#hello"); } } class MyTest : Test { public override void hello() { Console.WriteLine("MyTest#hello"); } } class YourTest : MyTest { public new void hello() { Console.WriteLine("YourTest#hello"); } } }
この結果はこう。
YourTest#hello MyTest#hello MyTest#hello
うーん。分かりづらい。
結局何が言いたかったかっていうと、C#多機能なのはいいがややこしい!っていうところでしょう。
がベストかなぁと思います。