ひでっぷの技術メモ

はてなダイアリーから移行しました

Java→C++、C#やる人の落とし穴? 〜virtualキーワード〜


 問1 下のようなクラスがある

グループ1(Java)

public class A{
public String hoge(){
return "hogehoge";
}
}


public class B extends A{
public String hoge(){
return "fugafuga";
}
}



グループ2(C++)

public class A{
public String hoge(){
return "hogehoge";
}
}


public class B : A{
public String hoge(){
return "fugafuga";
}
}


それぞれのグループにおいて下記のhogeメソッドはどんな文字列を返すか
A a = new B();
a.hoge();


答えは


グループ1は"fugafuga"
グループ2は"hogehoge"

C++をやってる人はそんなの当然って感じでしょう。
ただ、Javaから入ってC++やる人にはこれは大きな問題(見えないバグを生み出す)かもしれない。
おいらはC++の経験はあるのですが、オブジェクト指向をあまり理解していない時にちょろっとやったきりなので最初意味がわかりませんでした。

C++(とC++を基にしたC#)の仕様では親クラスのメソッドが走るそうです。
これを回避するためにはメソッドにvirtualキーワードをつけないといけません。

グループ2をグループ1と同じように"fugafuga"を結果として返す場合は


グループ2'(C++)

public class A{
public virtual String hoge(){
return "hogehoge";
}
}


public class B : A{
public String hoge(){
return "fugafuga";
}
}

さらにC#の場合は以下のようになります。


グループ3(C#)

public class A{
public virtual String hoge(){
return "hogehoge";
}
}


public class B : A{
public override String hoge(){
return "fugafuga";
}
}

C++より幾分親切になった気がしないでもないです。
逆説的に
子クラスでオーバーライドするメソッドにはoverrideがつくんだから親クラスのvirtualも忘れないでしょ。
って感じ。
子クラスのoverrideキーワードの有効性はわかります。
Javaでもよくあるのがメソッドをオーバーライドしたつもりがつづり間違いで別のメソッドを作ってたなんてバグ。
こんなバグはoverrideキーワードをつけることによってコンパイル時に見つけることができるでしょう。
Javaでもアノテーション型として@Overrideが導入されているくらいだし。
でもvirtualキーワードはどう?
おいらの解釈では正常に動いている親クラスのソースコードあえて書き換える必要があるんじゃないかと思うんだけど。
それって正常に動いているものはそのままにっていうオブジェクト指向の基本的な部分に反するんじゃないかなあ・・・。
おいら的にはプロパティといいこのvirtualといいなんだかC#は直感的じゃない。
Javaだとすっきりしている部分がC#はごちゃごちゃ回りくどい気がする。
会社の先輩はなんだかJavaよりC#のがソースコードを書く量が多いとも言っています。
これもなかなか的を射ているなあ。
どうもJavaの方がすっきりするのは自分がJavaから入ったからなのかなあ・・・