継承

 継承は、インヘリタンスとも呼ばれます。既に用意されているオブジェクトを基に、機能などを追加して新たなオブジェクトを作ることができる機能です。

 これから、Busクラスを作成してみましょう。バスは、人を乗せて運ぶことができますが、車と同じように進んだり、止まったりすることができます。つまり、Carクラスのような機能を持っています。「バスは車である」ということができます。このような関係を「is-a」の関係といいます(Bus is a Car)。

 このような場合、BusクラスはCarクラスの機能等を引き継いで作成することができます。Carクラスを継承してBusクラスを作ることができます。このようにすることで、Busにしかない属性、機能を記述すればよくなります。つまり、CarクラスとBusクラスの差分を記述するわけです。

 継承において、もとになるクラスをスーパークラスや基底クラスといい、それをもとに新しく作成するクラスをサブクラスや派生クラスといいます。

クラス継承の書式
class サブクラス名
 : スーパークラス名
{
 各種定義…
}

 継承の指定をした後、スーパークラスにはないフィールドやメソッドを追加や修正する記述をします。

○ プロジェクト

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

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

サンプルダウンロード

○ 作成の準備

 Busクラスを作成しましょう。「PropertyTest」をコピーしてプロジェクトを作成してください。

○ プログラム

 Busクラスを追加して、次のように記述してください。

Bus.cs

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

○ クラス図

○ 解説

 10行目でCarクラスを継承しています。これにより、Carクラスが持っているSpeedUpメソッド、SpeedDownメソッドが使えるようになります。

 13行目のプロパティは売上金額を扱います。乗客が乗車するたびに加算されていきます。このプロパティはsetアクセサーにprivate修飾子がついているので、設定はクラス内部からしかできないようになっています。14行目のプロパティは現在の乗客数を扱います。今回は50人まで乗せられるようにプログラムで制御しています。このプロパティも設定はクラス内部からしかできないようになっています。

 17~20行目ではコンストラクタを定義しています。このコンストラクタは引数なしで呼ばれると、オーバーロードしているガソリン量を受け取るコンストラクタを呼び出します。22~27行目では、ガソリン量を受け取るコンストラクタを定義しています。23行目はスーパークラスのコンストラクタを呼び出しています。「base」キーワードは、スーパークラスを表します。ここでのbaseキーワードはCarクラスを表します。

 31~47行目は乗車するメソッドです。このメソッドは運賃を受け取り乗車処理をします。その際、バスが走っていたり、乗客数が満員になっていたりすると乗車できないようにしています。いずれにも当てはまらない場合は、受け取った運賃を売上金額プロパティに加算し、乗客数プロパティを1人分増やします。

 50~65行目は降車するメソッドです。バスが走っていたり、乗客がいない場合は降車できないようにしています。いずれにも当てはまらない場合は、乗客数プロパティを1人分減らします。 

○ プログラム

 Busクラスを利用するプログラムを作成しましょう。次のように変更してください。

Program.cs

  1. class Program
  2. {
  3.  //バスの状態を表示するメソッド
  4.  static void ShowData(Bus bus)
  5.  {
  6.   Console.WriteLine("スピード:{0}km", bus.Speed);
  7.   Console.WriteLine("ガソリン:{0}L", bus.Gas);
  8.   Console.WriteLine("売上金額:{0}円", bus.SalesAmount);
  9.   Console.WriteLine("乗車人数:{0}人", bus.PassengerNumber);
  10.  }
  11.  static void Main(string[] args)
  12.  {
  13.   //インスタンスを生成する
  14.  Bus bus = new Bus(150);
  15.   //現在の状態を表示する
  16.  ShowData(bus);
  17.   while (true)
  18.   {
  19.    //操作を入力
  20.   Console.Write("1)加速 2)減速 3)給油 7)乗車 8)降車 9)終了:");
  21.    string inputdata = Console.ReadLine();
  22.    //操作によって分岐する
  23.    switch (inputdata)
  24.    {
  25.     case "1":
  26.      //加速する
  27.    bus.SpeedUp(5);
  28.    ShowData(bus);
  29.      break;
  30.     case "2":
  31.      //減速する
  32.    bus.SpeedDown(5);
  33.    ShowData(bus);
  34.     break;
  35.    case "3":
  36.      //給油する
  37.    bus.Gas = 80;
  38.    ShowData(bus);
  39.      break;
  40.   case "7":
  41.    //乗車する
  42.    string retride = bus.RideToBus(200);
  43.    if (retride == null)
  44.    {
  45.     ShowData(bus);
  46.    }
  47.    else
  48.    {
  49.    Console.WriteLine(retride);
  50.    }
  51.    break;
  52.   case "8":
  53.    //降車する
  54.    string retgetoff = bus.GetOffBus();
  55.    if (retgetoff == null)
  56.    {
  57.     ShowData(bus);
  58.    }
  59.    else
  60.    {
  61.     Console.WriteLine(retgetoff);
  62.    }
  63.    break;
  64.    case "9":
  65.     //プログラムを終了する
  66.     return;
  67.    }
  68.   }
  69.  }
  70. }

○ 解説

 23行目でBusオブジェクトを生成しています。BusオブジェクトはCarクラスを継承しているので今まで通り加速したり、減速したりできます。54行目では乗車メソッドを呼び出しています。戻り値がnullでない場合はエラーメッセージが返って来ているので、コンソールに表示しています。66行目では降車メソッドを呼び出しています。このメソッドは乗車メソッドと同様にエラーメッセージかnullが返ってくるのでそれに応じた処理をしています。

 今回はCarクラスを基にBusクラスを作成しました。BusクラスはCarクラスを継承しているので、Carクラスのメンバを記述しなくても使用することができます。ただし、privateになっているメンバは、継承したクラスでも直接アクセスすることができません。「protected」にすれば、直接操作できます。「protected」は、継承関係であればアクセスできますが、外部クラスからはアクセスすることができません。

 VC#では、サブクラスは1つのクラスから継承することができます。複数のクラスから継承させることはできません。(多重継承の禁止)

Busクラスのイメージ
Busクラスのイメージ

Busクラスのインスタンスを生成するときにBusクラスのコンストラクタを呼び出します。すると、初めにスーパークラスであるCarクラスのコンストラクタを呼び出します。サブクラスのコンストラクタでスーパークラスのコンストラクタの呼び出しが特に記述されていない場合、スーパークラスのデフォルトコンストラクタが呼び出されれます。もし、スーパークラスで引数を持つコンストラクタが定義されていると、デフォルトコンストラクタは仮定されないので、サブクラスでスーパークラスのコンストラクタの呼び出しを記述しなければなりません。

インスタンス生成の手順
インスタンス生成の手順

前へ   次へ