派生クラスから基底クラスのメンバーにアクセスする

完了

基底クラスのメソッドまたはプロパティを置換またはオーバーライドする派生クラスは、base キーワードを使用して基底クラスのメソッドまたはプロパティに引き続きアクセスできます。 これにより、派生クラスのオーバーライドされたメンバーから基底クラスのコンストラクター、メソッド、およびプロパティを呼び出すことができます。 base キーワードを使用すると、派生クラスが基底クラスによって提供される機能を適切に再利用および拡張することを確認できます。

base キーワードは、次のタスクを実行するために使用されます。

  • 派生クラスのオーバーライドされたメソッドから基底クラス メソッドを呼び出す。
  • 派生クラスのコンストラクター内から基底クラスコンストラクターを実装する。

base キーワードには、次の制限があります。

  • base キーワードは、コンストラクター、インスタンス メソッド、またはインスタンス プロパティ アクセサーでのみ使用できます。
  • base キーワードは静的メソッドでは使用できません。 静的メソッドで base キーワードを使用しようとすると、エラーが発生します。

派生クラスに base キーワードを実装する場合、コードはクラス宣言で指定された基底クラスを使用します。 たとえば、クラス宣言でクラス ClassC : ClassB を指定した場合、base キーワードを使用すると、コードは ClassBから ClassC のメンバーにアクセスできます。 クラス ClassB がクラス ClassAから継承するかどうかは関係ありません。

派生クラスから基底クラスのプロパティとメソッドにアクセスする

継承を実装する場合、派生クラスから基底クラスのプロパティとメソッドにアクセスすることが一般的な要件です。 次のコードは、base キーワードを実装するための構文を示しています。

base.MemberName

base キーワードと基底クラス メンバーの名前はピリオド (.) で区切られています。 MemberName には、基底クラスのプロパティ、メソッド、またはフィールドを指定できます。

次のコードは、派生クラスから基底クラスのプロパティとメソッドにアクセスする方法を示しています。


// create an instance of the derived classes
DerivedClass1 derivedClass1 = new DerivedClass1();

// demonstrate the overridden methods of the derived class
Console.WriteLine("Calling the methods of DerivedClass1...\n");
Console.WriteLine($"Method1 in the derived class overrides the base class and provides a custom message: {derivedClass1.Method1()}");

derivedClass1.Method2();

/*Output:
Calling the methods of DerivedClass1...

Method1 in the base class is abstract and can't be called.
Method1 in the derived class overrides the base class and provides a custom message: Message from the overridden Method1 in DerivedClass1

Method2 in the derived class calls base.Method2 (reuses the base class implementation)
Method2 in the base class implements common behavior and returns true/false
Method2 in the derived class accesses base class Property2: Base - Property2

Method2 in the derived class uses base class members to modify and extend functionality
*/

public abstract class BaseClass
{
    public abstract string Property1 { get; set; }
    public virtual string Property2 { get; set; } = "Base - Property2";

    public abstract string Method1();

    public virtual bool Method2()
    {
        Console.WriteLine("Method2 in the base class implements common behavior and returns true/false");
        return true;
    }
}

public class DerivedClass1 : BaseClass
{
    public override string Property1 { get; set; } = "Derived - Property1";
    public new string Property2 { get; set; } = "Derived - Property2";

    public override string Method1()
    {
        // Method1 of the base class is abstract and can't be called
        Console.WriteLine($"Method1 in the base class is abstract and can't be called.");
        
        // Return the base.Method1 response additional information specific to DerivedClass1
        return $"Message from the overridden Method1 in DerivedClass1";
    }

    public override bool Method2()
    {
        // Call base class method to implement common behavior
        Console.WriteLine($"\nMethod2 in the derived class calls base.Method2 (reuses the base class implementation)");
        bool baseMethod2Success = base.Method2();

        // Access base class Property2
        string baseProperty2Value = base.Property2;
        Console.WriteLine($"Method2 in the derived class accesses base class Property2: {baseProperty2Value}");

        // implement derived class logic that involves base class information
        if (baseMethod2Success && baseProperty2Value == "Base - Property2")
        {
            Console.WriteLine("\nMethod2 in the derived class uses base class members to modify and extend functionality");
            return true;
        }
        else
        {
            Console.WriteLine("Method2 in the derived class can implement alternate behavior");
        }

        return false;
    }
}

このコード サンプルでは、DerivedClass1 クラスは BaseClass から継承し、そのメソッドをオーバーライドして機能を拡張します。 このコードでは、次の手順を実装します。

  1. DerivedClass1 のインスタンスは、ステートメント DerivedClass1 derivedClass1 = new DerivedClass1();を使用して作成されます。 この派生クラス インスタンスは、派生クラスのオーバーライドされたメソッドを呼び出して示すために使用されます。

  2. このコードは、Method1 ステートメント内から派生クラスの Console.WriteLine を呼び出します。 オーバーライドされた Method1 は、基底クラスの抽象 Method1 にアクセスできません。 代わりに、派生クラスに固有であることを示す文字列を返す独自の実装を提供します。

  3. このコードは、派生クラスの Method2 を呼び出します。 オーバーライドされた Method2 は、基底クラスの base.Method2 実装を再利用するために Method2 を使用します。 このメソッドは基底クラスの Property2 にアクセスし、その値を出力します。 オーバーライドされたメソッドは、基底クラスの Method2 によって返されるブール値と Property2の値を使用して、Method2 機能を拡張するか、代替動作を実装します。 この手順では、派生クラスが基底クラス メソッドの動作を構築および変更する方法を示します。

手記

仮想メンバーは、base を使用して、独自の実装でそのメンバーの基底クラスの実装を呼び出すのがベスト プラクティスです。 基底クラスの動作を発生させることで、派生クラスは派生クラスに固有の動作の実装に集中できます。 基底クラスの実装が呼び出されない場合、基底クラスの動作と互換性のある動作を行うには、派生クラスが必要です。

派生クラスから基底クラスコンストラクターにアクセスする

基底クラスのクラス コンストラクターには、base キーワードを使用して派生クラスのコンストラクターからアクセスできます。

次のコードは、派生クラスから基底クラスコンストラクターにアクセスする方法を示しています。


// create an instance of the derived classes
DerivedClass1 derivedClass1 = new DerivedClass1("Derived1 - Property1", "Derived1 - Property2");

// demonstrate the overridden methods of the derived class
Console.WriteLine("Calling the methods of DerivedClass1...\n");
Console.WriteLine($"Method1 in the derived class appends derived class information to the return value: {derivedClass1.Method1()}");

derivedClass1.Method2();

/*Output:
Calling the methods of DerivedClass1...

Method1 in the derived class calls base.Method1. base.Method1 returns: base.Method1 results
Method1 in the derived class appends derived class information to the return value: base.Method1 results - plus information specific to DerivedClass1

Method2 in the derived class calls base.Method2 (reuses the base class implementation)
Method2 in the base class implements common behavior and returns true/false
Method2 in the derived class accesses base class Property2: Base - Property2

Method2 in the derived class uses base class members to modify and extend functionality
*/

public abstract class BaseClass
{
    public abstract string Property1 { get; set; }
    public virtual string Property2 { get; set; }

    public BaseClass(string property1, string property2)
    {
        Property1 = property1;
        Property2 = property2;
    }

    public virtual string Method1()
    {
        return "base.Method1 results";
    }

    public virtual bool Method2()
    {
        Console.WriteLine("Method2 in the base class implements common behavior and returns true/false");
        return true;
    }
}

public class DerivedClass1 : BaseClass
{
    public override string Property1 { get; set; }
    public new string Property2 { get; set; }

    public DerivedClass1(string property1, string property2) : base(property1, "Base - Property2")
    {
        Property1 = property1;
        Property2 = property2;
    }

    public override string Method1()
    {
        // Method1 of the base class is now virtual
        Console.WriteLine($"Method1 in the derived class calls base.Method1. base.Method1 returns: {base.Method1()}");
        
        // Return the base.Method1 response additional information specific to DerivedClass1
        return $"{base.Method1()} - plus information specific to DerivedClass1";
    }

    public override bool Method2()
    {
        // Call base class method to implement common behavior
        Console.WriteLine($"\nMethod2 in the derived class calls base.Method2 (reuses the base class implementation)");
        bool baseMethod1Success = base.Method2();

        // Access base class Property2
        string baseProperty2Value = base.Property2;
        Console.WriteLine($"Method2 in the derived class accesses base class Property2: {baseProperty2Value}");

        // implement derived class logic that involves base class information
        if (baseMethod1Success && baseProperty2Value == "Base - Property2")
        {
            Console.WriteLine("\nMethod2 in the derived class uses base class members to modify and extend functionality");
            return true;
        }
        else
        {
            Console.WriteLine("Method2 in the derived class can implement alternate behavior");
        }

        return false;
    }
}

派生クラス コンストラクターから基底クラス コンストラクターを呼び出すことは重要です。 たとえば、基底クラスコンストラクターが、派生クラスによって使用される共通プロパティを初期化する場合などです。 派生クラス コンストラクターから基底クラス コンストラクターを呼び出すことで、派生クラス コンストラクターが実行される前に共通プロパティが初期化されるようにします。

次のコードについて考えてみましょう。


public abstract class Vehicle
{
    public virtual int Speed { get; set; }
    public virtual int Fuel { get; set; }

    public Vehicle(int speed, int fuel)
    {
        Speed = speed;
        Fuel = fuel;
    }

    public virtual void Drive()
    {
        Console.WriteLine("Vehicle is driving");
    }
}

public class Car : Vehicle
{
    public int NumberOfDoors { get; set; }
    public int TrunkCapacity { get; set; }

    public Car(int speed, int fuel, int numberOfDoors) : base(speed, fuel)
    {
        NumberOfDoors = numberOfDoors;
        // Initialize TrunkCapacity based on the Speed and Fuel properties of the base class
        TrunkCapacity = CalculateTrunkCapacity(Speed, Fuel);
    }

    private int CalculateTrunkCapacity(int speed, int fuel)
    {
        // Example logic to calculate trunk capacity based on speed and fuel
        return (speed + fuel) / 2;
    }

    public override void Drive()
    {
        base.Drive();
        Console.WriteLine("Car is driving with additional features");
    }
}

class Program
{
    static void Main()
    {
        Car car = new Car(100, 50, 4);
        Console.WriteLine($"Speed: {car.Speed}, Fuel: {car.Fuel}, NumberOfDoors: {car.NumberOfDoors}, TrunkCapacity: {car.TrunkCapacity}");
        car.Drive();
    }
}

Car クラス コンストラクターは、base キーワードを使用して基底クラス コンストラクターを呼び出していることに注意してください。 最初に基底クラス コンストラクターを呼び出すと、Speed クラス コンストラクターが実行される前に、Fuel 基底クラスの Vehicle プロパティと Car プロパティが正しく初期化されます。 TrunkCapacity クラスの Car プロパティは、Speed 基底クラスの Fuel プロパティと Vehicle プロパティを使用して初期化されるため、この一連のイベントは重要です。

概要

派生クラスから基底クラスのメンバーにアクセスする場合は、次のガイドラインを考慮してください。

  • 派生クラスから基底クラスメンバーにアクセスするには、base キーワードを使用します。
  • base キーワードを使用して、派生クラス コンストラクターから基底クラスコンストラクターを呼び出します。
  • 派生クラスでオーバーライドされたメソッドから基底クラスのフィールド、プロパティ、およびメソッドにアクセスするには、base キーワードを使用します。