オーバーライド

 サブクラスはスーパークラスのメンバを継承することができますが、状況によってはスーパークラスの処理の内容を変更しなくてはならない場合があります。サブクラス側で同じメソッド名でかつ、同じシグネチャ(引数の構成)のメソッドを再び定義することができます。これをメソッドのオーバーライド(override)と呼びます。

 例えば、Carクラスでは、スピードの制限がありません。基本的に無限にスピードが出るように設計されています。しかし、Busではスピードの制限を設けないと危険なので、速度の制限を設けたいと思います。

Busクラスでオーバーライド
Busクラスでオーバーライド

 では、Busクラスの定義を修正してみましょう。オーバーライドするためには、スーパークラス側と、サブクラス側でオーバーライドの指定をしなくてはなりません。

■ オーバーライドされる側

 public virtual void SpeedUp(int sp)
 {
  ・・・
 }

■ オーバーライドする側

 public override void SpeedUp(int sp)
 {
  ・・・
 }

○ プロジェクト

 プロジェクトを作成して確認してみましょう。

プロジェクトの種類 コンソール アプリケーション
プロジェクト名 OverrideTest

サンプルダウンロード

○ 作成の準備

 Busクラスにメソッドを追加しましょう。「InheritanceTest」をコピーしてプロジェクトを作成してください。

○ プログラム

 まず、CarクラスのSpeedUpメソッドにvirtualキーワードを追加します。

Car.cs

  1. class Car
  2. {
  3.  //フィールド==========
  4.  private int speed;  //スピード
  5.  private double gas;  //ガソリン情報
  1.  //メソッド==========
  2.  //加速させるメソッド
  3.  public virtual void SpeedUp(int sp)
  4.  {
  5.   //ガソリンを減らす
  6.   this.gas -= sp / 10.0;
  7.   if(this.gas < 0)  //ガソリンがマイナスになる場合
  8.   {
  9.    //ガソリンを0に補正し、スピードを増やさない
  10.    this.gas = 0;
  11.   }
  12.   else
  13.   {
  14.    //スピードを増やす
  15.    this.speed += sp;
  16.   }
  17.  }
  18.  //減速させるメソッド
  19.  public void SpeedDown(int sp)
  20.  {
  21.   //スピードを減らす
  22.   this.speed -= sp;
  23.   if(this.speed < 0)  //スピードがマイナスになる場合
  24.   {
  25.    //スピードを0に補正する
  26.    this.speed = 0;
  27.   }
  28.  }
  29. }

○ 解説

 55行目のメソッドの定義でvirtualキーワードを追加しました。これにより、Carクラスを継承したクラスでSpeedUpメソッドをオーバーライドできるようになります。

○ プログラム

 次に、BusクラスにSpeedUpメソッドを追加します。

Bus.cs

  1. class Bus
  2.  : Car
  3. {
  4.  //プロパティ==========
  5.  public int SalesAmount { get; private set; }  //運賃
  6.  public int PassengerNumber { get; private set; }  //乗客人数
  1.  //メソッド==========
  2.  //乗車させるメソッド
  3.  public string RideToBus(int fare)
  4.  {
  5.   //走行中かどうか
  6.   if (this.Speed != 0)
  7.   {
  8.    return "停車してください。";
  9.   }
  10.   //満席かどうか
  11.   if (this.PassengerNumber >= 50)
  12.   {
  13.    return "満席のため、乗車できません。";
  14.   }
  15.   //料金と、乗車人数を加算
  16.   this.SalesAmount += fare;
  17.   this.PassengerNumber++;
  18.   return null;
  19.  }
  20.  //降車させるメソッド
  21.  public string GetOffBus()
  22.  {
  23.   //走行中かどうか
  24.   if (this.Speed != 0)
  25.   {
  26.    return "停車してください。";
  27.    }
  28.   //乗客がいるかどうか
  29.   if (this.PassengerNumber == 0)
  30.   {
  31.    return "乗客はいません。";
  32.   }
  33.   //乗車人数を減算
  34.   this.PassengerNumber--;
  35.   return null;
  36.  }
  37.  //加速させるメソッド(オーバーライド)
  38.  public override void SpeedUp(int sp)
  39.  {
  40.   if ((this.Speed + sp) <= 60)
  41.   {
  42.    base.SpeedUp(sp);
  43.   }
  44.  }
  45. }

○ クラス図

○ 解説

 68~74行目でoverrideキーワードを指定してSpeedUpメソッドを再定義しています。このメソッドは加速後のスピードが60km/h以下ならスーパークラスであるCarクラスのSpeedUpメソッドを呼び出して加速しています。baseキーワードはスーパークラスを指すので、base.XXと指定することでスーパークラスのメンバを指定することができます。

 プログラムの修正はこれで終了です。Busクラスを利用するプログラムは修正をしませんが、60km/hまでしかスピードが出ないようになっています。これは実際のバスの運転手がバスのアクセルを踏むと自動的に60kmまでしかスピードが出なくなる状況と似ています。もしオーバーライドができないと次のようにメソッドを用意することになるかもしれません。

オーバーロードを使わないと
オーバーロードを使わないと

 上の図の例だとBusクラスを利用する側では「SpeedUp」と「SpeedUpForBus」というメソッドのどちらを呼び出すかを選択することになります。実際のバスの例だと、無限にスピードが出るアクセルと、60kmまでしかスピードが出ないアクセルが2つ並んでいる状態ということができます。バスの操作説明書には、「アクセルは2つありますが、必ず60㎞/hまでしかスピードが出ないアクセルを踏むようにしてください」とあったとしても、操作ミスで無限にスピードが出るアクセルを踏んでしまうかもしれませんし、スピード狂の運転手であれば、リミッターのかからない(無限にスピードが出る)アクセルをあえて踏むかもしれません。

 オーバーライドで「SpeeUp」メソッドを再定義することにより、実際のバスでアクセルは1つあるという状態を作り出すことができます。これにより、バスを安全に運用してもらうことが可能になりますし、運転手を再教育する必要はなくなるということになります。それは、使用している部品がバージョンアップしても、使い方は変わらない(プログラムを変更しなくてもよい)ということになります。

前へ   次へ