ブルーノのC#プログラミング & unity勉強日記

プログラミング素人、ブルーノの自主勉強ノートです。他のプログラミングを勉強したい方の助けになれば幸いです。その他趣味の雑記もしていきたいです

オーバーライドについて

f:id:covory10101101276:20171002221035j:plain

みなさんこんにちは🌚

講義が忙しすぎて試合とバイトとトリプルブッキングでつらたんのブルーノです。「天使にラブソングを」をみたのですが最高でしたね。洋画のノリは大好きです笑。シスター見習いのシスター・メアリー・ロバート役のWendy Makkenaがとても可愛いですね。

 

さて今回はオーバーライドという言葉についてです。とってもかっこいい響きで以前やったオーバーロードに通じるものがありますがオーバーロードとは別物です。

オーバーライドについて

前回やった継承は基本クラスのメソッドの内容に新たに加えるだけでなく、すでにある内容を書き換えることもできます。これにより、一つのメソッドから複数のバージョンのメソッドを作ることができます。これをオーバーライドと言います。ロックマンエグゼで例えるならバリアブルソードみたいなものです。一つの同じチップで様々なタイプの攻撃ができるようになるみたいなものです。さて、オーバーライドされる元のメソッドを仮想メソッド(virtual method)と言い、オーバーライドされた後のメソッドをオーバーライドメソッド(override method)と言います。オーバーライドメソッドを組む上では以下のような細かいルールがあります。

  • アクセス修飾子は同じでなければならない
  • シグニチャは同じでなければならない
  • 静的メソッドはオーバーライドできない

言われてみればまあそうかと思うかもしれませんが結構忘れやすいので注意しましょう。

さてオーバーライドの方法ですがいたって簡単で、基本クラスのメソッドにvirtualキーワードをつけておき、派生クラスで同じ名前のメソッドの前にoverrideキーワードをつけるだけです。

例)

class Base

{

    public virtual void Main()

    { ... }

}

class Derived : Base

{

     public override void Main()

    { ... }

}

 

今までやってきたノリならば簡単ですね。しかしここで一つの疑問が浮かびます。前回やった「名前の隠蔽」です。同じ名前にすれば基本クラスのメソッドは無視されるというこのルールがある上でオーバーライドとの違いはなんなのでしょうか。ここからが少し理解が難しいところです。

下の画像をみてください

f:id:covory10101101276:20171007051525p:plain

f:id:covory10101101276:20171007051532p:plain

f:id:covory10101101276:20171007051538p:plain

名前の隠蔽を使ったTaroクラスとオーバーライドを使ったMateクラスで検証を行いました。検証の順番が少々ごっちゃですが許してください😂

1つ目の画像がそれぞれの継承について、2つ目が様々な方法で定義した各クラスの継承、3つ目がその結果についてです。主に2つ目の画像をみていただきたいのですがまずp1とp2インスタンスは名前の隠蔽を用いて普通に通常の方法で継承しているので、結果は予想通りです。注目すべきは3つ目と5つ目で、右辺で宣言した変数の型と左辺で生成したインスタンスの参照の型が違っています。結果はどうでしょうか。名前の隠蔽のPersonクラスの方は基本クラスのままの文章を返すのに対し、オーバーライドしたPeopleクラスは継承されたmateクラスの文章を返しています。これはつまり、名前の隠蔽による継承は「コンパイル時に参照する変数の値に応じてメソッドが決定される」のに対し、オーバーライドは「実行時に生成されたオブジェクトの型によりメソッドが決定される」ことを表しています。前者は動かない入れ物である変数により決定するので静的な型によるものとされ、後者は実行時に決定されるため動的メソッドディスパッチと呼ばれます。

”箱”である参照変数ではなく生成したオブジェクトの型通りにメソッドが動くのはオブジェクトの特徴によって振る舞いが決定するということであり、これがオブジェクト指向プログラミングの重要な要素の一つ「多態性」というものです。いちいち変数でなく自分が定義したメソッド通りに実行されて欲しいのは当然で、こういった時のためにオーバーライドは便利です。

プロパティやインデクサのオーバーロード

メソッドだけでなく、プロパティやインデクサもオーバーライドすることができます。

例)

・プロパティ

class Base

{

    public virtual string Prop

    { get, set; }

}

class Derived : Base

{

    public override string Prop    

    { get, set; }

}

 

・インデクサ

class Base

{

    public virtual string this[string index]

    { get, set; }

}

class Derived : Base

{

    public virtual string this[string index]

    { get, set; }

}

具体的にプログラムを組むとこんな感じです

プロパティ

f:id:covory10101101276:20171010110814p:imagef:id:covory10101101276:20171010110819p:imagef:id:covory10101101276:20171010110822p:image

無属性のロングソードのデータを入れたBruno029クラスから派生させたBruno030クラス(火属性)とBruno031クラス(氷属性)をそれぞれオーバーライドさせています。なおどちらの属性のソードもソード系統であるのは変わらないのでKeitouクラスはconstキーワードで変更できないようにしています。ロックマンエグゼでは各属性ソードチップにはお世話になりました

 

インデクサ

f:id:covory10101101276:20171010180512p:imagef:id:covory10101101276:20171010180515p:imagef:id:covory10101101276:20171010180521p:imagef:id:covory10101101276:20171010180523p:image

オーバーライドさせたインデクサの方は偶数個めのインデクサにのみ入れることができるので奇数は弾かれます。今回はここまでにしておきます

 

オーバーライドを使うことですでにあるクラスを様々なタイプに使い分けることができ、とても便利になります。ずいぶん時間がかかりましたがこの記事をまとめている間とても有意義で楽しかったです。