派生クラスのプロパティとメソッドをオーバーライドする
C# では、override キーワードを使用して、派生クラスの基底クラスの動作を拡張または変更できます。
override キーワードを使用すると、基底クラスから継承されたプロパティとメソッドをオーバーライドし、派生クラスにカスタム実装を提供できます。 これにより、基底クラスで定義されているコードを再利用し、派生クラスの基底クラスの動作を拡張または変更できます。
派生クラスのプロパティまたはメソッドをオーバーライドするには、次の手順に従う必要があります。
- 基底クラスのメンバーを
abstractまたはvirtualとして宣言します。 - 派生クラスのメンバーをオーバーライドします。
- 必要に応じて、
baseキーワードを使用して、派生クラスのオーバーライドされたメンバーから基底クラスの実装にアクセスします。
基底クラスの抽象メンバーと仮想メンバーを宣言する
派生クラスのメンバーをオーバーライドする前に、基底クラスのメンバーを abstract または virtualとして宣言する必要があります。
- 抽象:
abstractキーワードは、メンバーに実装がなく、派生クラスでオーバーライドする必要があることを示します。 - Virtual:
virtualキーワードは、メンバーに実装があるが、派生クラスでオーバーライドまたは拡張できることを示します。
次の例では、基底クラスで抽象メンバーと仮想メンバーを宣言する方法を示します。
public class BaseClass
{
public string Property1 { get; set; } = "Base - Property1";
public string Property2 { get; set; } = "Base - Property2";
public virtual void Method1()
{
Console.WriteLine("Base - Method1");
}
public void Method2()
{
Console.WriteLine("Base - Method2");
}
}
派生クラスのメンバーをオーバーライドする
基底クラスのメンバーを abstract または virtualとして宣言した後、override キーワードを使用して派生クラスのメンバーをオーバーライドできます。
override キーワードは、派生クラスのメンバーが基底クラスのメンバーをオーバーライドすることを示します。
次の例を考えてみましょう。
// Step 1: Create instances of the base class and the derived classes
BaseClass baseClass = new BaseClass();
DerivedClass derivedClass = new DerivedClass();
BaseClass baseClassReferencingDerivedClass = new DerivedClass();
// Step 2: Access properties and methods of the base class
Console.WriteLine($"\n{baseClass.Property1}");
Console.WriteLine($"{baseClass.Property2}");
baseClass.Method1();
baseClass.Method2();
// Step 3: Access properties and methods of the derived class
Console.WriteLine($"\n{derivedClass.Property1}");
Console.WriteLine($"{derivedClass.Property2}");
derivedClass.Method1();
derivedClass.Method2();
// Step 4: Access properties and methods of the base class that references the derived class
Console.WriteLine($"\n{baseClassReferencingDerivedClass.Property1}");
Console.WriteLine($"{baseClassReferencingDerivedClass.Property2}");
baseClassReferencingDerivedClass.Method1();
baseClassReferencingDerivedClass.Method2();
/*Output:
Base - Property1
Base - Property2
Base - Method1
Base - Method2
Derived - Property1
Derived - Property2
Derived - Method1
Derived - Method2
Derived - Property1
Base - Property2
Derived - Method1
Base - Method2
*/
public class BaseClass
{
public virtual string Property1 { get; set; } = "Base - Property1";
public virtual string Property2 { get; set; } = "Base - Property2";
public virtual void Method1()
{
Console.WriteLine("Base - Method1");
}
public void Method2()
{
Console.WriteLine("Base - Method2");
}
}
public class DerivedClass : BaseClass
{
public override string Property1 { get; set; } = "Derived - Property1";
public new string Property2 { get; set; } = "Derived - Property2";
public override void Method1()
{
Console.WriteLine("Derived - Method1");
}
public new void Method2()
{
Console.WriteLine("Derived - Method2");
}
}
このコードでは、override キーワードと new キーワードを使用して、派生クラスのプロパティとメソッドを変更および非表示にする方法を示します。 このコードでは、基底クラス (BaseClass) と基底クラスから継承する派生クラス (DerivedClass) を定義します。 基底クラスには、2 つのプロパティ (Property1 と Property2) と 2 つのメソッド (Method1 と Method2) があります。 派生クラスは Property1 と Method1 をオーバーライドし、new キーワードを使用して Property2 と Method2 を非表示にします。
コードの内訳を次に示します。
手順 1 では、基底クラス (
baseClass)、派生クラス (derivedClass) のインスタンス、および基底クラス変数 (baseClassReferencingDerivedClass) によって参照される派生クラスのインスタンスを作成します。baseClassReferencingDerivedClassインスタンスは、基底クラス参照が派生クラス オブジェクトを指すポリモーフィズムを示します。手順 2 では、コードは基底クラス インスタンスのプロパティとメソッドにアクセスして出力します。
baseClassはBaseClassのインスタンスであるため、BaseClassで定義されているプロパティとメソッドを使用します。 出力には、基底クラスで定義されている値と動作が表示されます。手順 3 では、コードは派生クラス インスタンスのプロパティとメソッドにアクセスして出力します。
derivedClassはDerivedClassのインスタンスであるため、DerivedClassで定義されているオーバーライドされたプロパティとメソッドを使用します。 出力には、派生クラスで定義されている値と動作が反映されます。手順 4 では、コードは基底クラス変数によって参照される派生クラス インスタンスのプロパティとメソッドにアクセスして出力します。 オーバーライドされるプロパティとメソッド (
Property1およびMethod1) の場合、派生クラスの実装が使用されます。 ただし、非表示 (Property2およびMethod2) のプロパティとメソッドの場合は、基底クラスの実装が使用されます。 これは、メソッドのオーバーライド (overrideを使用) とメソッドの非表示 (newを使用) の違いを示しています。
抽象基底クラスの定義
基底クラスを abstractとして定義する場合は、クラスが不完全であり、派生クラスによって実装する必要があることを示します。 抽象クラスには、派生クラスによって実装する必要がある抽象プロパティとメソッドを含めることができます。 抽象基底クラスは直接インスタンス化できないため、抽象メンバーを実装するための派生クラスのテンプレートとして使用されます。
次の例を考えてみましょう。
// create instances of the base class and the derived classes
// Note: We can't create an instance of an abstract class
// BaseClass baseClass = new BaseClass(); // This line would cause a compile-time error
DerivedClass derivedClass = new DerivedClass();
BaseClass baseClassReferencingDerivedClass = new DerivedClass();
// access properties and methods of the derived class
Console.WriteLine($"\n{derivedClass.Property1}");
Console.WriteLine($"{derivedClass.Property2}");
derivedClass.Method1();
derivedClass.Method2();
// access properties and methods of the base class that references the derived class
Console.WriteLine($"\n{baseClassReferencingDerivedClass.Property1}");
Console.WriteLine($"{baseClassReferencingDerivedClass.Property2}");
baseClassReferencingDerivedClass.Method1();
baseClassReferencingDerivedClass.Method2();
/*Output:
Derived - Property1
Derived - Property2
Derived - Method1
Derived - Method2
Derived - Property1
Base - Property2
Derived - Method1
Base - Method2
*/
public abstract class BaseClass
{
public abstract string Property1 { get; set; }
public virtual string Property2 { get; set; } = "Base - Property2";
public abstract void Method1();
public void Method2()
{
Console.WriteLine("Base - Method2");
}
}
public class DerivedClass : BaseClass
{
public override string Property1 { get; set; } = "Derived - Property1";
public new string Property2 { get; set; } = "Derived - Property2";
public override void Method1()
{
Console.WriteLine("Derived - Method1");
}
public new void Method2()
{
Console.WriteLine("Derived - Method2");
}
}
基底クラスが abstract キーワードを使用して宣言されている場合、基底クラスを直接インスタンス化できないことに注意してください。 代わりに、抽象メンバーを実装する派生クラスのインスタンスを作成する必要があります。 派生クラスは、基底クラスで定義されている抽象メンバーの実装を提供する必要があります。 抽象でないメンバーは、派生クラスでオーバーライドまたは非表示にすることができます。
Object クラスの暗黙的に継承されたメンバーをオーバーライドする
C# のすべてのクラスは、Object クラスから暗黙的に継承されます。
Object クラスは、ToString、Equals、GetHashCodeなど、すべてのクラスによって継承される複数のメンバーを定義します。 クラス内のこれらのメンバーをオーバーライドして、カスタム実装を提供できます。
次の例を考えてみましょう。
// create instances of the derived classes
DerivedClass1 derivedClass1 = new DerivedClass1();
DerivedClass2 derivedClass2a = new DerivedClass2 { Property1 = "Value1", Property2 = "Value2" };
DerivedClass2 derivedClass2b = new DerivedClass2 { Property1 = "Value1", Property2 = "Value2" };
DerivedClass2 derivedClass2c = new DerivedClass2 { Property1 = "Value3", Property2 = "Value4" };
// demonstrate Object class methods for DerivedClass1
Console.WriteLine("\nDemonstrating Object class methods for DerivedClass1:");
Console.WriteLine($"ToString: {derivedClass1.ToString()}");
Console.WriteLine($"Equals: {derivedClass1.Equals(new DerivedClass1())}");
Console.WriteLine($"GetHashCode: {derivedClass1.GetHashCode()}");
// demonstrate overridden Object class methods for DerivedClass2
Console.WriteLine("\nDemonstrating overridden Object class methods for DerivedClass2:");
Console.WriteLine($"ToString: {derivedClass2a.ToString()}");
Console.WriteLine($"Equals (derivedClass2a vs derivedClass2b): {derivedClass2a.Equals(derivedClass2b)}"); // should return true
Console.WriteLine($"Equals (derivedClass2a vs derivedClass2c): {derivedClass2a.Equals(derivedClass2c)}"); // should return false
Console.WriteLine($"GetHashCode (derivedClass2a): {derivedClass2a.GetHashCode()}");
Console.WriteLine($"GetHashCode (derivedClass2b): {derivedClass2b.GetHashCode()}");
Console.WriteLine($"GetHashCode (derivedClass2c): {derivedClass2c.GetHashCode()}");
/*Output:
Demonstrating Object class methods for DerivedClass1:
ToString: DerivedClass1
Equals: False
GetHashCode: [HashCode]
Demonstrating overridden Object class methods for DerivedClass2:
ToString: DerivedClass2: Property1 = Value1, Property2 = Value2
Equals (derivedClass2a vs derivedClass2b): True
Equals (derivedClass2a vs derivedClass2c): False
GetHashCode (derivedClass2a): [HashCode]
GetHashCode (derivedClass2b): [HashCode]
GetHashCode (derivedClass2c): [HashCode]
*/
public abstract class BaseClass
{
public abstract string Property1 { get; set; }
public virtual string Property2 { get; set; } = "Base - Property2";
public abstract void Method1();
public void Method2()
{
Console.WriteLine("Base - Method2");
}
}
public class DerivedClass1 : BaseClass
{
public override string Property1 { get; set; } = "Derived1 - Property1";
public new string Property2 { get; set; } = "Derived1 - Property2";
public override void Method1()
{
Console.WriteLine("Derived1 - Method1");
}
public new void Method2()
{
Console.WriteLine("Derived1 - Method2");
}
}
public class DerivedClass2 : BaseClass
{
public override string Property1 { get; set; } = "Derived2 - Property1";
public new string Property2 { get; set; } = "Derived2 - Property2";
public override void Method1()
{
Console.WriteLine("Derived2 - Method1");
}
public new void Method2()
{
Console.WriteLine("Derived2 - Method2");
}
// Override ToString method
public override string ToString()
{
return $"DerivedClass2: Property1 = {Property1}, Property2 = {Property2}";
}
// Override Equals method
public override bool Equals(object obj)
{
if (obj is DerivedClass2 other)
{
return Property1 == other.Property1 && Property2 == other.Property2;
}
return false;
}
// Override GetHashCode method
public override int GetHashCode()
{
return HashCode.Combine(Property1, Property2);
}
}
この例では、DerivedClass1 クラスと DerivedClass2 クラスは、BaseClass クラスから継承します。
DerivedClass2 クラスは、ToString クラスから継承された Equals、GetHashCode、および Object メソッドをオーバーライドします。
ToString メソッドはオブジェクトの文字列表現を返し、Equals メソッドは 2 つのオブジェクトを等しいかどうかを比較し、GetHashCode メソッドはオブジェクトのハッシュ コードを返します。
DerivedClass2 クラスは、オブジェクトのプロパティを表示し、そのプロパティに基づいてオブジェクトを比較するために、これらのメソッドのカスタム実装を提供します。
概要
派生クラスのプロパティとメソッドをオーバーライドすると、基底クラスの動作を拡張または変更できます。
override キーワードを使用すると、基底クラスから継承されるプロパティとメソッドのカスタム実装を提供できます。 これにより、基底クラスで定義されているコードを再利用し、派生クラスの基底クラスの動作を拡張または変更できます。
new キーワードを使用して、基底クラスのプロパティとメソッドを非表示にし、派生クラスに新しい実装を提供することもできます。