この記事は、C#言語を使ったクラスの継承について記載したものです。以下の記事を、依頼元の指示に従って書き直しました。
本記事で参照しているテキストを以下に示します。
「独習C#」 山田祥寛著、翔泳社発行
クラスを作る意味は、ソフトウェアの部品化の促進です。システムの開発効率を高めるには、プログラムを資産として蓄える必要があります。毎回何もかもを最初から開発していては時間がかかりすぎるため、既にあるものはそのまま使おうという発想です。部品になったソフトウェアは、あとで組み合わせて使えて、開発工数を削減できます。
ある分野の処理を行うプログラムをクラスにしておくと、あとで再利用することができます。例えば、システム的なものとしてはファイル読み書きに関するクラス、画面表示に関するクラス、数値計算に関するクラスなど。業務的なものとしては受注クラス、出荷クラス、売上クラスなどです。
良く設計されたクラスは、必要最低限の情報しか利用者に見せません。テキストの8.1節にテレビの例が載っています。テレビの中にはさまざまな回路が入っていますが、利用者はせいぜい主電源、チャンネルボタン、音量ボタンくらいしか使いません。利用者はテレビが映る仕組みを知らなくてもテレビを見られます。
このような、情報の隠ぺいを「カプセル化」といいます。プログラマは、カプセル化を意識してプログラミングをすることになります。
クラスの復習は、以上です。
既にあるクラスを再利用して新たな機能を付け加えたり違う動作をさせたい場合、次の2つの方法があります。
1. クラスを修正する
2. クラスを継承する
自分(自社、自部門)が持っているクラスであれば、クラスを修正することが可能です。しかし、開発効率向上のためにソフトウェアの再利用を推進している組織では、自分の想いだけでクラスを修正することはできません。ソフトウェアは資産ですので、既にテストが済んでいるソフトウェア資産を修正することは、バグを混入させる可能性があるため、上位レベル(上司、開発プロジェクト、品質管理部門など)の承認が要ります。そのため、重要な・役に立つ機能追加・修正でないと、承認されにくいです。
もちろん趣味のプログラミングや自分以外に関わる人がいないプログラムであれば、自由にクラスを作り変えてかまいません。
大元のクラスを修正せずに機能を追加したり修正したい場合は、大元のクラスの特徴を引き継いで新しい別のクラスを作ります。このことをクラスを継承するといいます。クラスを継承するなら、ソフトウェアの再利用を推進している組織でも上位レベルの承認が要りません。
大元のクラスを基底クラスといいます。参考書によっては基本クラス、親クラス、スーパークラスと呼んだりもしますが全部同じ意味です。継承して作る新しいクラスを派生クラスといいます。子クラス、サブクラスと呼ぶこともあります。
テキスト366ページにあるPersonクラスを継承し、BusinessPersonクラスを定義してみましょう。まず、基底クラスとなるPersonクラスです。Personクラスは、姓と名前を受け取ってShow()メソッドで表示するだけのプログラムです。
namespace inherit1.Person
{
internal class Person
{
// 自動プロパティ
public string FirstName { get; set; } = "";
public string LastName { get; set; } = "";
public string Show()
{
return $"名前は{this.LastName}{this.FirstName}です。";
}
}
}
クラスを継承するには、クラスを定義するときに「 : 基底クラス」と書きます。Personを継承してBusinessPersonクラスを作るのは、このようにします。BusinessPersonクラスは、Work()メソッドで姓名を受け取って働いていると表示するプログラムです。テキスト378ページにソースがあります。
using inherit1.Person;
internal class BusinessPerson : Person
{
public string Work()
{
return $"{this.LastName}{this.FirstName}は、働きます。";
}
}
インスタンスを作り、メソッドを呼び出してみましょう。BusinessPersonクラスにShow()メソッドはありませんが、Personクラスを継承しているのでShow()を呼び出せることを確認してください。
using System;
internal class InheritBasic
{
static void Main(string[] args)
{
var p = new Person
{
FirstName = "太郎",
LastName = "山田"
};
Console.WriteLine("==== 基底クラスの出力 ====");
Console.WriteLine(p.Show()); // 結果:名前は山田太郎です。
var bp = new BusinessPerson
{
FirstName = "花子",
LastName = "鈴木"
};
Console.WriteLine("==== 派生クラスの出力 ====");
Console.WriteLine(bp.Work()); // 結果:鈴木花子は、働きます。
Console.WriteLine(bp.Show()); // 結果:名前は鈴木花子です。
}
}
実行結果はこのようになります。
クラスA、B、...を継承してクラスXを作ることを、多重継承といいます。
クラスAのみを継承してクラスXを作ることを、単一継承といいます。
これに関するテキストを読んだら、クイズをやってみましょう。
C#のクラスは多重継承ができる。〇 or × ?
C#で、クラスAを継承してクラスBを定義した。それでは、クラスBを継承して、クラスCを定義することはできるか。〇 or × ?
クラスを継承するとき、基底クラスのメソッドを同じ名前で書き換える仕組みをオーバーライドといいます。書き換える意味は、基底クラスと同じ使い方を利用者に提供することです。
車クラスにアクセルというメソッドがあったとします。アクセルを踏むと、スピードを10キロ加速します。車クラスを継承して軽自動車クラスを作りました。軽自動車クラスでは、アクセルを踏んだら5キロ加速するようにしたいです。その場合、基底クラスのアクセルはそのままで、新しくアクセル2というメソッドを作った方いいでしょうか?いいえ、そのまま同じアクセルという名前で使いたいはずです。
オーバーライドを使えば、メソッド名はアクセルのままで動きを変えることができます。
再び、Personクラスを例にとって説明します。オーバーライドを使うときは、virtualとoverrideというキーワードをペアで使います。まず、基底となるPersonクラスです。さきほどとの違いは、Show()にvirtualがついています。
namespace inherit3.Person
{
internal class Person
{
// 自動プロパティ
public string FirstName { get; set; } = "";
public string LastName { get; set; } = "";
// 仮想メソッドを定義
public virtual string Show()
{
return $"名前は{this.LastName}{this.FirstName}です。";
}
}
}
次に派生クラスのBusinessPersonです。こちらは、Show()にoverrideキーワードがついています。
using inherit3.Person;
// 派生クラス
internal class BusinessPerson : Person
{
// 基底クラスの同名のメソッドをオーバーライド(上書き)
public override string Show()
{
return $"会社員の{this.LastName}{this.FirstName}です。";
}
public string Work()
{
return $"{this.LastName}{this.FirstName}は、働きます。";
}
}
インスタンスを作り、メソッドを呼び出してみましょう。Show()の呼び出し方は変わっていませんが、動作が変わっていることを確認してください。
using System;
internal class OverrideBasic
{
static void Main(string[] args)
{
var bp = new BusinessPerson
{
FirstName = "花子",
LastName = "鈴木"
};
Console.WriteLine(bp.Work()); // 結果:鈴木花子は、働きます。
Console.WriteLine(bp.Show()); // 結果:会社員の鈴木花子です。
}
}
オーバーライドは、基底となるクラスがオーバーライドを想定してvirtual指定をしているときに使用可能となります。そのため、基底となるクラスの設計がより重要となります。
以上