継承 (C# プログラミング ガイド)

更新 : 2008 年 7 月

継承は、カプセル化やポリモーフィズムと共に、オブジェクト指向プログラミングの重要な 3 つの特性 ("柱") の 1 つです。継承を使用すると、他のクラスで定義されている動作を再利用、拡張、および変更する新しいクラスを作成できます。メンバが継承される側のクラスを基本クラスと呼び、メンバを継承する側のクラスを派生クラスと呼びます。

ms173149.alert_note(ja-jp,VS.90).gifメモ :

構造体では、継承はサポートされませんが、インターフェイスを実装することはできます。詳細については、「インターフェイス (C# プログラミング ガイド)」を参照してください。

概念的には、派生クラスは基本クラスから特化したクラスです。たとえば、基本クラス Animal がある場合、Mammal という名前の派生クラスと、Reptile という名前の別の派生クラスを作成できます。Mammal は Animal の 1 つであり、Reptile も Animal の 1 つですが、それぞれの派生クラスは、基本クラスからの別々の特化を表します。

別のクラスから派生するクラスを定義するとき、派生クラスには、基本クラスのコンストラクタとデストラクタを除くすべてのメンバが暗黙的に引き継がれます。したがって、派生クラスでは、基本クラスのコードを再実装しなくても再利用できます。派生クラスにメンバを追加することもできます。このような方法で、派生クラスは基本クラスの機能を拡張します。

次の図は、あるビジネス プロセスにおける作業項目を表す WorkItem クラスを示します。すべてのクラスと同様に、このクラスは System.Object から派生し、そのすべてのメソッドを継承します。WorkItem には、独自のメンバが 5 つ追加されています。これにはコンストラクタが含まれます。コンストラクタは継承されないためです。ChangeRequest は、WorkItem から継承し、特定の種類の作業項目を表します。ChangeRequest には、WorkItem および Object から継承されるメンバの他に、2 つのメンバが追加されています。1 つは、独自のコンストラクタを追加する必要があるためです。もう 1 つとして、変更が適用される元の WorkItem に ChangeRequest を関連付けるためのメンバが追加されています。

クラスの継承
クラスの継承

次の例は、前の図に示したクラスの関係が C# でどのように表現されるかを示しています。また、この例は、WorkItem で仮想メソッド Object.ToString をオーバーライドする方法と、ChangeRequest クラスで WorkItem のメソッドの実装を継承する方法も示しています。

// WorkItem implicitly inherits from Object class
public class WorkItem
{
    private static int nextID;
    protected int ID { get; set; }
    protected TimeSpan jobLength { get; set; }
    protected string Title { get; set; }
    protected string Description { get; set; }
    // Default constructor
    public WorkItem() 
    {
        ID = 0;
        Title = "Default title";
        Description = "Default description.";
        jobLength = new TimeSpan();
    }
    // Static constructor for static member.
    static WorkItem()
    {
        nextID = 0;
    }
    // Instance constructor.
    public WorkItem( string title, string desc, TimeSpan joblen)
    {
        this.ID = GetNextID();                
        this.Title = title;
        this.Description = desc;
        this.jobLength = joblen;
    }
    protected int GetNextID()
    {
       return ++nextID;
    }
    public void Update(string title, TimeSpan joblen)
    {
        this.Title = title;
        this.jobLength = joblen;
    }

    // Virtual method override.
    public override string ToString()
    {
        return String.Format("{0} - {1}", this.ID, this.Title); 
    }
}

// ChangeRequest derives from WorkItem and adds two of its own members.
public class ChangeRequest : WorkItem
{
    protected int originalItemID {get; set;}
    public ChangeRequest() { }
    public ChangeRequest(string title, string desc, TimeSpan jobLen, int originalID)
    {
        this.ID = GetNextID();
        this.Title = title;
        this.Description = desc;
        this.jobLength = jobLen;
        this.originalItemID = originalID;
    }
}

class Program
{
    static void Main()
    {
        WorkItem item = new WorkItem(                                
                        "Fix Bugs", 
                        "Fix all bugs in my source code branch",
                        new TimeSpan(3, 4, 0, 0));

        ChangeRequest change = new ChangeRequest("Change design of base class",
                                                 "Add members to base class",
                                                 new TimeSpan(4, 0, 0),
                                                 1);

        Console.WriteLine(item.ToString());

        // ChangeRequest inherits WorkItem's override of ToString
        Console.WriteLine(change.ToString()); 

        // Keep the console open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/* Output:
    1 - Fix Bugs
    2 - Change design of base class
*/

抽象メソッドと仮想メソッド

基本クラスでメソッドが virtual として宣言されている場合、派生クラスはそのメソッドを独自の実装でオーバーライドできます。基本クラスでメンバが abstract として宣言されている場合は、クラスから直接継承される非抽象クラスで、そのメソッドをオーバーライドする必要があります。派生クラス自体が抽象クラスの場合は、抽象メンバを実装せずに継承します。抽象メンバと仮想メンバは、オブジェクト指向プログラミングの重要な特性の 2 つ目であるポリモーフィズムの基礎です。詳細については、「ポリモーフィズム (C# プログラミング ガイド)」を参照してください。

抽象基本クラス

new キーワードを使用した直接のインスタンス化を禁止する場合は、クラスを abstract として宣言できます。このようにすると、そのクラスは、新しいクラスを派生させなければ使用できなくなります。抽象クラスには、それ自身が abstract として宣言された 1 つ以上のメソッド シグネチャを含むことができます。これらのシグネチャはパラメータと戻り値を指定しますが、実装 (メソッド本体) は持ちません。抽象クラスは必ずしも抽象メンバを含む必要はありませんが、クラスに抽象メンバが含まれている場合は、クラス自体を抽象クラスとして宣言する必要があります。それ自身が抽象クラスでない派生クラスは、抽象基本クラスから継承した抽象メソッドをすべて実装する必要があります。詳細については、「抽象クラスとシール クラス、およびクラス メンバ (C# プログラミング ガイド)」および「抽象クラスのデザイン」を参照してください。

インターフェイス

インターフェイスは、抽象メンバだけで構成される抽象基本クラスに似た参照型です。インターフェイスから派生するクラスは、そのインターフェイスのすべてのメンバを実装する必要があります。1 つのクラスで複数のインターフェイスを実装できますが、直接継承できる基本クラスは 1 つだけです。

インターフェイスは、必ずしも "is-a" 関係を持たない、クラスの特定の機能を定義するために使用します。たとえば、ある型の 2 つのオブジェクトが等しいかどうかをクライアント コードで判別できるようにする (ただし、等価性の定義は型によって行う) 場合は、そのクラスまたは構造体で IEquatable[`1] インターフェイスを実装できます。IEquatable<T> は、基本クラスと派生クラスの間に存在する is-a 関係 ("Mammal は Animal である" など) と同様の意味を示すものではありません。詳細については、「インターフェイス (C# プログラミング ガイド)」を参照してください。

派生クラスによる基本クラスのメンバへのアクセス

派生クラスは、基本クラスのパブリック メンバ、プロテクト メンバ、内部メンバ、およびプロテクト内部メンバにアクセスできます。派生クラスは基本クラスのプライベート メンバを継承しますが、これらのメンバにはアクセスできません。ただし、これらのすべてのプライベート メンバは派生クラスにも存在し、基本クラス自体で行われるのと同じ処理を実行できます。たとえば、基本クラスのプロテクト メソッドがプライベート フィールドにアクセスするとします。継承された基本クラスのメソッドが正しく動作するためには、派生クラス内にそのフィールドが存在する必要があります。

それ以上の派生の禁止

クラス自身またはメンバを sealed として宣言することで、他のクラスがそのクラスやメンバを継承できないように指定できます詳細については、「抽象クラスとシール クラス、およびクラス メンバ (C# プログラミング ガイド)」を参照してください。

派生クラスによる基本クラスのメンバの隠ぺい

派生クラスでは、同じ名前とシグネチャでメンバを宣言することで、基本クラスのメンバを隠ぺいできます。new 修飾子を使用すると、そのメンバが基本メンバのオーバーライドとして用意されているのではないことを明示的に指定できます。new の使用は必須ではありませんが、new を使用しない場合は、コンパイラの警告が生成されます。詳細については、「Override キーワードと New キーワードによるバージョン管理 (C# プログラミング ガイド)」および「Override キーワードと New キーワードを使用する場合について (C# プログラミング ガイド)」を参照してください。

参照

概念

C# プログラミング ガイド

参照

クラスと構造体 (C# プログラミング ガイド)

class (C# リファレンス)

struct (C# リファレンス)

履歴の変更

日付

履歴

理由

2008 年 7 月

コンテンツ、図、および新しい例を追加

情報の拡充