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

継承は、カプセル化およびポリモーフィズムと共に、オブジェクト指向プログラミングの主要な 3 つの特性の 1 つです。Inheritance, together with encapsulation and polymorphism, is one of the three primary characteristics of object-oriented programming. 継承を使用すると、他のクラスで定義されている動作を再利用、拡張、変更して新しいクラスを作成できます。Inheritance enables you to create new classes that reuse, extend, and modify the behavior defined in other classes. メンバーが継承される側のクラスを "基底クラス" と呼び、メンバーを継承する側のクラスを "派生クラス" と呼びます。The class whose members are inherited is called the base class, and the class that inherits those members is called the derived class. 派生クラスは、直接の基底クラスを 1 つだけ持つことができます。A derived class can have only one direct base class. ただし、継承は推移的です。However, inheritance is transitive. ClassCClassB から派生し、ClassBClassA から派生している場合、ClassC では、ClassBClassA で宣言されているメンバーが継承されます。If ClassC is derived from ClassB, and ClassB is derived from ClassA, ClassC inherits the members declared in ClassB and ClassA.

注意

構造体では、継承がサポートされていませんが、インターフェイスを実装することはできます。Structs do not support inheritance, but they can implement interfaces. 詳細については、「インターフェイス」を参照してください。For more information, see Interfaces.

概念的には、派生クラスは基底クラスから特化したクラスです。Conceptually, a derived class is a specialization of the base class. たとえば、基底クラス Animal がある場合、Mammal という名前の派生クラスと、Reptile という名前の別の派生クラスを持つことができます。For example, if you have a base class Animal, you might have one derived class that is named Mammal and another derived class that is named Reptile. MammalAnimal であり、ReptileAnimal ですが、各派生クラスは、基底クラスから別々の特殊化を表します。A Mammal is an Animal, and a Reptile is an Animal, but each derived class represents different specializations of the base class.

インターフェイス宣言では、そのメンバーの既定の実装を定義できます。Interface declarations may define a default implementation for its members. そのような実装は、派生インターフェイスと派生インターフェイスを実装するクラスによって継承されます。These implementations are inherited by derived interfaces, and by classes that implement those interfaces. 既定のインターフェイス メソッドの詳細については、インターフェイスに関する記事の言語リファレンスのセクションをご覧ください。For more information on default interface methods, see the article on interfaces in the language reference section.

クラスを別のクラスから派生するように定義すると、派生クラスには、コンストラクターとファイナライザーを除く、基底クラスのすべてのメンバーが暗黙的に引き継がれます。When you define a class to derive from another class, the derived class implicitly gains all the members of the base class, except for its constructors and finalizers. 派生クラスでは、基底クラスのコードを再実装することなく再利用します。The derived class reuses the code in the base class without having to reimplement it. 派生クラスでは、メンバーを追加できます。You can add more members in the derived class. 派生クラスでは、基底クラスの機能が拡張されます。The derived class extends the functionality of the base class.

次の図は、あるビジネス プロセスの作業項目を表す WorkItem クラスを示しています。The following illustration shows a class WorkItem that represents an item of work in some business process. 他のすべてのクラスと同様に、System.Object から派生し、そのすべてのメソッドを継承します。Like all classes, it derives from System.Object and inherits all its methods. WorkItem には、独自のメンバーが 5 つ追加されています。WorkItem adds five members of its own. そのようなメンバーにはコンストラクターが含まれます。コンストラクターは継承されないためです。These members include a constructor, because constructors aren't inherited. WorkItem から継承される ChangeRequest クラスは、特定の種類の作業項目を表します。Class ChangeRequest inherits from WorkItem and represents a particular kind of work item. ChangeRequest には、WorkItemObject から継承したメンバーに 2 つのメンバーが追加されます。ChangeRequest adds two more members to the members that it inherits from WorkItem and from Object. 独自のコンストラクターを追加する必要があるほか、さらに originalItemID も追加されます。It must add its own constructor, and it also adds originalItemID. originalItemID プロパティを使用すると、ChangeRequest インスタンスは、変更要求が適用される元の WorkItem と関連付けることができます。Property originalItemID enables the ChangeRequest instance to be associated with the original WorkItem to which the change request applies.

クラスの継承を示す図

次の例は、前の図に示したクラスの関係が C# でどのように表現されるかを示しています。The following example shows how the class relationships demonstrated in the previous illustration are expressed in C#. また、WorkItem が仮想メソッド Object.ToString をオーバーライドする方法と、ChangeRequest クラスが WorkItem によるメソッドの実装を継承する方法も示しています。The example also shows how WorkItem overrides the virtual method Object.ToString, and how the ChangeRequest class inherits the WorkItem implementation of the method. 最初のブロックでクラスが定義されます。The first block defines the classes:

// WorkItem implicitly inherits from the Object class.
public class WorkItem
{
    // Static field currentID stores the job ID of the last WorkItem that
    // has been created.
    private static int currentID;

    //Properties.
    protected int ID { get; set; }
    protected string Title { get; set; }
    protected string Description { get; set; }
    protected TimeSpan jobLength { get; set; }

    // Default constructor. If a derived class does not invoke a base-
    // class constructor explicitly, the default constructor is called
    // implicitly.
    public WorkItem()
    {
        ID = 0;
        Title = "Default title";
        Description = "Default description.";
        jobLength = new TimeSpan();
    }

    // Instance constructor that has three parameters.
    public WorkItem(string title, string desc, TimeSpan joblen)
    {
        this.ID = GetNextID();
        this.Title = title;
        this.Description = desc;
        this.jobLength = joblen;
    }

    // Static constructor to initialize the static member, currentID. This
    // constructor is called one time, automatically, before any instance
    // of WorkItem or ChangeRequest is created, or currentID is referenced.
    static WorkItem() => currentID = 0;

    // currentID is a static field. It is incremented each time a new
    // instance of WorkItem is created.
    protected int GetNextID() => ++currentID;

    // Method Update enables you to update the title and job length of an
    // existing WorkItem object.
    public void Update(string title, TimeSpan joblen)
    {
        this.Title = title;
        this.jobLength = joblen;
    }

    // Virtual method override of the ToString method that is inherited
    // from System.Object.
    public override string ToString() =>
        $"{this.ID} - {this.Title}";
}

// ChangeRequest derives from WorkItem and adds a property (originalItemID)
// and two constructors.
public class ChangeRequest : WorkItem
{
    protected int originalItemID { get; set; }

    // Constructors. Because neither constructor calls a base-class
    // constructor explicitly, the default constructor in the base class
    // is called implicitly. The base class must contain a default
    // constructor.

    // Default constructor for the derived class.
    public ChangeRequest() { }

    // Instance constructor that has four parameters.
    public ChangeRequest(string title, string desc, TimeSpan jobLen,
                         int originalID)
    {
        // The following properties and the GetNexID method are inherited
        // from WorkItem.
        this.ID = GetNextID();
        this.Title = title;
        this.Description = desc;
        this.jobLength = jobLen;

        // Property originalItemId is a member of ChangeRequest, but not
        // of WorkItem.
        this.originalItemID = originalID;
    }
}

この次のブロックでは、基底クラスと派生クラスの使用方法が示されます。This next block shows how to use the base and derived classes:

// Create an instance of WorkItem by using the constructor in the
// base class that takes three arguments.
WorkItem item = new WorkItem("Fix Bugs",
                            "Fix all bugs in my code branch",
                            new TimeSpan(3, 4, 0, 0));

// Create an instance of ChangeRequest by using the constructor in
// the derived class that takes four arguments.
ChangeRequest change = new ChangeRequest("Change Base Class Design",
                                        "Add members to the class",
                                        new TimeSpan(4, 0, 0),
                                        1);

// Use the ToString method defined in WorkItem.
Console.WriteLine(item.ToString());

// Use the inherited Update method to change the title of the
// ChangeRequest object.
change.Update("Change the Design of the Base Class",
    new TimeSpan(4, 0, 0));

// ChangeRequest inherits WorkItem's override of ToString.
Console.WriteLine(change.ToString());
/* Output:
    1 - Fix Bugs
    2 - Change the Design of the Base Class
*/

抽象メソッドと仮想メソッドAbstract and virtual methods

基底クラスによってメソッドが virtual として宣言されるとき、派生クラスでは、その独自の実装でそのメソッドをoverrideできます。When a base class declares a method as virtual, a derived class can override the method with its own implementation. 基底クラスによってメンバーが abstract として宣言される場合、そのクラスから直接継承されるあらゆる非抽象クラスでそのメソッドをオーバーライドする必要があります。If a base class declares a member as abstract, that method must be overridden in any non-abstract class that directly inherits from that class. 派生クラス自体が抽象クラスである場合は、抽象メンバーを実装することなく継承します。If a derived class is itself abstract, it inherits abstract members without implementing them. 抽象メンバーと仮想メンバーは、オブジェクト指向プログラミングの重要な特性の 2 つ目であるポリモーフィズムの基礎です。Abstract and virtual members are the basis for polymorphism, which is the second primary characteristic of object-oriented programming. 詳細については、「ポリモーフィズム」を参照してください。For more information, see Polymorphism.

抽象基底クラスAbstract base classes

new 演算子を使用して直接インスタンス化されないようにする場合は、クラスを abstract として宣言できます。You can declare a class as abstract if you want to prevent direct instantiation by using the new operator. 抽象クラスは、新しいクラスがそれから誘導される場合にのみ利用できます。An abstract class can be used only if a new class is derived from it. 抽象クラスには、それ自体が abstract として宣言された 1 つ以上のメソッド シグネチャを含めることができます。An abstract class can contain one or more method signatures that themselves are declared as abstract. これらのシグネチャは、パラメーターと戻り値を指定しますが、実装 (メソッドの本体) は持ちません。These signatures specify the parameters and return value but have no implementation (method body). 抽象クラスには抽象メンバーを含める必要がありません。ただし、クラスに抽象メンバーが含まれる場合、そのクラス自体を抽象として宣言する必要があります。An abstract class doesn't have to contain abstract members; however, if a class does contain an abstract member, the class itself must be declared as abstract. それ自体が抽象ではない派生クラスの場合、抽象基底クラスから抽象メソッドを実装する必要があります。Derived classes that aren't abstract themselves must provide the implementation for any abstract methods from an abstract base class. 詳細については、「抽象クラスとシール クラス、およびクラス メンバー」を参照してください。For more information, see Abstract and Sealed Classes and Class Members.

インターフェイスInterfaces

"インターフェイス" は、一連のメンバーを定義する参照型です。An interface is a reference type that defines a set of members. そのインターフェイスを実装するすべてのクラスと構造体で、その一連のメンバーを実装する必要があります。All classes and structs that implement that interface must implement that set of members. インターフェイスでは、それらのメンバーの一部または全部に対して既定の実装を定義できます。An interface may define a default implementation for any or all of these members. クラスは、直接的には 1 つの基底クラスからしか派生できませんが、複数のインターフェイスを実装できます。A class can implement multiple interfaces even though it can derive from only a single direct base class.

インターフェイスは、"is a" 関係を必ずしも持たないクラスに特定の機能を定義する目的で使用されます。Interfaces are used to define specific capabilities for classes that don't necessarily have an "is a" relationship. たとえば、System.IEquatable<T> インターフェイスをクラスまたは構造体によって実装し、特定の型の 2 つのオブジェクトが等しいかどうかを判断できます (もっとも等価性は型で定義されます)。For example, the System.IEquatable<T> interface can be implemented by any class or struct to determine whether two objects of the type are equivalent (however the type defines equivalence). IEquatable<T> では、基底クラスと派生クラスの間に存在する同じ種類の "is a" 関係 (たとえば、MammalAnimal である) を意味しません。IEquatable<T> doesn't imply the same kind of "is a" relationship that exists between a base class and a derived class (for example, a Mammal is an Animal). 詳細については、「インターフェイス」を参照してください。For more information, see Interfaces.

後続の派生を禁止するPreventing further derivation

クラスでは、それ自体かメンバーを sealed として宣言することで、他のクラスがそのクラスまたはそのメンバーから継承することを禁止できます。A class can prevent other classes from inheriting from it, or from any of its members, by declaring itself or the member as sealed. 詳細については、「抽象クラスとシール クラス、およびクラス メンバー」を参照してください。For more information, see Abstract and Sealed Classes and Class Members.

派生クラスで基底クラス メンバーを隠ぺいするDerived class hiding of base class members

派生クラスは、同じ名前とシグネチャでメンバーを宣言することで、基底クラスのメンバーを隠ぺいすることができます。A derived class can hide base class members by declaring members with the same name and signature. new 修飾子を利用すると、メンバーが基底メンバーのオーバーライドではないことを明示的に示すことができます。The new modifier can be used to explicitly indicate that the member isn't intended to be an override of the base member. new の使用は必須ではありませんが、new が使用されていない場合、コンパイラの警告が生成されます。The use of new isn't required, but a compiler warning will be generated if new isn't used. 詳細については、「Override キーワードと New キーワードによるバージョン管理」および「Override キーワードと New キーワードを使用する場合について」を参照してください。For more information, see Versioning with the Override and New Keywords and Knowing When to Use Override and New Keywords.

関連項目See also