Override キーワードと New キーワードを使用する場合について (C# プログラミング ガイド)Knowing When to Use Override and New Keywords (C# Programming Guide)

C# では、派生クラスのメソッドを基底クラスのメソッドと同じ名前にすることができます。In C#, a method in a derived class can have the same name as a method in the base class. new および override キーワードを使って、メソッドでの処理を指定できます。You can specify how the methods interact by using the new and override keywords. override 修飾子は基底クラスの virtualメソッドを "拡張" し、new 修飾子はアクセス可能な基底クラスのメソッドを "非表示" にします。The override modifier extends the base class virtual method, and the new modifier hides an accessible base class method. このトピックの例ではその違いを示します。The difference is illustrated in the examples in this topic.

コンソール アプリケーションで、次の 2 つのクラス BaseClassDerivedClass を宣言します。In a console application, declare the following two classes, BaseClass and DerivedClass. DerivedClassBaseClassを継承します。DerivedClass inherits from BaseClass.

class BaseClass  
{  
    public void Method1()  
    {  
        Console.WriteLine("Base - Method1");  
    }  
}  
  
class DerivedClass : BaseClass  
{  
    public void Method2()  
    {  
        Console.WriteLine("Derived - Method2");  
    }  
}  

Main メソッドで、変数 bcdcbcdc を宣言します。In the Main method, declare variables bc, dc, and bcdc.

  • bcBaseClass 型であり、その値は BaseClass です。bc is of type BaseClass, and its value is of type BaseClass.

  • dcDerivedClass 型であり、その値は DerivedClass です。dc is of type DerivedClass, and its value is of type DerivedClass.

  • bcdcBaseClass 型であり、その値は DerivedClass です。bcdc is of type BaseClass, and its value is of type DerivedClass. この変数には注意する必要があります。This is the variable to pay attention to.

bcbcdcBaseClass 型なので、キャストを使わない限り、直接アクセスできるのは Method1 だけです。Because bc and bcdc have type BaseClass, they can only directly access Method1, unless you use casting. 変数 dc は、Method1Method2 の両方にアクセスできます。Variable dc can access both Method1 and Method2. これらの関係を次のコードに示します。These relationships are shown in the following code.

class Program  
{  
    static void Main(string[] args)  
    {  
        BaseClass bc = new BaseClass();  
        DerivedClass dc = new DerivedClass();  
        BaseClass bcdc = new DerivedClass();  
  
        bc.Method1();  
        dc.Method1();  
        dc.Method2();  
        bcdc.Method1();  
    }  
    // Output:  
    // Base - Method1  
    // Base - Method1  
    // Derived - Method2  
    // Base - Method1  
}  

次に、以下の Method2 メソッドを BaseClass に追加します。Next, add the following Method2 method to BaseClass. このメソッドのシグネチャは、DerivedClassMethod2 メソッドのシグネチャと一致します。The signature of this method matches the signature of the Method2 method in DerivedClass.

public void Method2()  
{  
    Console.WriteLine("Base - Method2");  
}  

BaseClassMethod2 メソッドを追加したので、次のコードに示すように、BaseClass の変数 bc および bcdc に 2 つめの呼び出しステートメントを追加できます。Because BaseClass now has a Method2 method, a second calling statement can be added for BaseClass variables bc and bcdc, as shown in the following code.

bc.Method1();  
bc.Method2();  
dc.Method1();  
dc.Method2();  
bcdc.Method1();  
bcdc.Method2();  

プロジェクトをビルドすると、BaseClassMethod2 メソッドを追加したことで警告が発生するようになります。When you build the project, you see that the addition of the Method2 method in BaseClass causes a warning. 警告の内容は、DerivedClassMethod2 メソッドが BaseClassMethod2 メソッドを隠ぺいしているというものです。The warning says that the Method2 method in DerivedClass hides the Method2 method in BaseClass. それが意図する結果である場合は、Method2 の定義で new キーワードを使うことをお勧めします。You are advised to use the new keyword in the Method2 definition if you intend to cause that result. または、どちらかの Method2 メソッドの名前を変更して警告を解決することもできますが、実用的ではない場合があります。Alternatively, you could rename one of the Method2 methods to resolve the warning, but that is not always practical.

new を追加する前に、プログラムを実行して、追加した呼び出しステートメントによって生成される出力を確認します。Before adding new, run the program to see the output produced by the additional calling statements. 次のような結果が表示されます。The following results are displayed.

// Output:  
// Base - Method1  
// Base - Method2  
// Base - Method1  
// Derived - Method2  
// Base - Method1  
// Base - Method2  

new キーワードは、その出力を生成する関係を維持しますが、警告を抑制します。The new keyword preserves the relationships that produce that output, but it suppresses the warning. BaseClass 型の変数は引き続き BaseClass のメンバーにアクセスし、DerivedClass 型の変数は引き続き最初に DerivedClass のメンバーにアクセスした後、BaseClass から継承されたメンバーを考慮します。The variables that have type BaseClass continue to access the members of BaseClass, and the variable that has type DerivedClass continues to access members in DerivedClass first, and then to consider members inherited from BaseClass.

警告を抑制するには、次のコードで示すように、DerivedClass での Method2 の定義に new 修飾子を追加します。To suppress the warning, add the new modifier to the definition of Method2 in DerivedClass, as shown in the following code. 修飾子を追加する位置は、public の前でも後でもかまいません。The modifier can be added before or after public.

public new void Method2()  
{  
    Console.WriteLine("Derived - Method2");  
}  

もう一度プログラムを実行し、出力が変わらないことを確認します。Run the program again to verify that the output has not changed. また、警告が表示されなくなったことを確認します。Also verify that the warning no longer appears. new を使うことにより、それによって修飾されるメンバーが基底クラスから継承されたメンバーを隠ぺいすることを了解していることを明示します。By using new, you are asserting that you are aware that the member that it modifies hides a member that is inherited from the base class. 継承による名前の非表示について詳しくは、「new 修飾子」をご覧ください。For more information about name hiding through inheritance, see new Modifier.

この動作を override を使ったときの効果と比較するため、次のメソッドを DerivedClass に追加します。To contrast this behavior to the effects of using override, add the following method to DerivedClass. override 修飾子を追加する位置は、public の前でも後でもかまいません。The override modifier can be added before or after public.

public override void Method1()  
{  
    Console.WriteLine("Derived - Method1");  
}  

BaseClass での Method1 の定義に virtual 修飾子を追加します。Add the virtual modifier to the definition of Method1 in BaseClass. virtual 修飾子を追加する位置は、public の前でも後でもかまいません。The virtual modifier can be added before or after public.

public virtual void Method1()  
{  
    Console.WriteLine("Base - Method1");  
}  

プロジェクトを再度実行します。Run the project again. 次の出力の最後の 2 行に特に注意してください。Notice especially the last two lines of the following output.

// Output:  
// Base - Method1  
// Base - Method2  
// Derived - Method1  
// Derived - Method2  
// Derived - Method1  
// Base - Method2  

override 修飾子を使うことで、bcdc は、DerivedClass で定義されている Method1 メソッドにアクセスできます。The use of the override modifier enables bcdc to access the Method1 method that is defined in DerivedClass. 通常、これは継承階層での必要な動作です。Typically, that is the desired behavior in inheritance hierarchies. 派生クラスから作成される値を持つオブジェクトには、派生クラスで定義されているメソッドを使うことが必要とされます。You want objects that have values that are created from the derived class to use the methods that are defined in the derived class. そのような動作は、override を使って基底クラスのメソッドを拡張することで実現できます。You achieve that behavior by using override to extend the base class method.

ここまでの例をすべて含んだコードを次に示します。The following code contains the full example.

using System;  
using System.Text;  
  
namespace OverrideAndNew  
{  
    class Program  
    {  
        static void Main(string[] args)  
        {  
            BaseClass bc = new BaseClass();  
            DerivedClass dc = new DerivedClass();  
            BaseClass bcdc = new DerivedClass();  
  
            // The following two calls do what you would expect. They call  
            // the methods that are defined in BaseClass.  
            bc.Method1();  
            bc.Method2();  
            // Output:  
            // Base - Method1  
            // Base - Method2  
  
            // The following two calls do what you would expect. They call  
            // the methods that are defined in DerivedClass.  
            dc.Method1();  
            dc.Method2();  
            // Output:  
            // Derived - Method1  
            // Derived - Method2  
  
            // The following two calls produce different results, depending   
            // on whether override (Method1) or new (Method2) is used.  
            bcdc.Method1();  
            bcdc.Method2();  
            // Output:  
            // Derived - Method1  
            // Base - Method2  
        }  
    }  
  
    class BaseClass  
    {  
        public virtual void Method1()  
        {  
            Console.WriteLine("Base - Method1");  
        }  
  
        public virtual void Method2()  
        {  
            Console.WriteLine("Base - Method2");  
        }  
    }  
  
    class DerivedClass : BaseClass  
    {  
        public override void Method1()  
        {  
            Console.WriteLine("Derived - Method1");  
        }  
  
        public new void Method2()  
        {  
            Console.WriteLine("Derived - Method2");  
        }  
    }  
}  

次の例では、異なるコンテキストでの同様の動作を示します。The following example illustrates similar behavior in a different context. この例では、3 つのクラスが定義されています。基底クラス Car と、それから派生される 2 つのクラス ConvertibleCarMinivan です。The example defines three classes: a base class named Car and two classes that are derived from it, ConvertibleCar and Minivan. 基底クラスには、DescribeCar メソッドが含まれます。The base class contains a DescribeCar method. このメソッドは、車の基本的な説明を表示した後、ShowDetails を呼び出して追加情報を提供します。The method displays a basic description of a car, and then calls ShowDetails to provide additional information. これら 3 つのクラスのそれぞれで、ShowDetails メソッドが定義されています。Each of the three classes defines a ShowDetails method. new 修飾子は、ConvertibleCar クラスで ShowDetails を定義するために使われています。The new modifier is used to define ShowDetails in the ConvertibleCar class. override 修飾子は、Minivan クラスで ShowDetails を定義するために使われています。The override modifier is used to define ShowDetails in the Minivan class.

// Define the base class, Car. The class defines two methods,  
// DescribeCar and ShowDetails. DescribeCar calls ShowDetails, and each derived  
// class also defines a ShowDetails method. The example tests which version of  
// ShowDetails is selected, the base class method or the derived class method.  
class Car  
{  
    public void DescribeCar()  
    {  
        System.Console.WriteLine("Four wheels and an engine.");  
        ShowDetails();  
    }  
  
    public virtual void ShowDetails()  
    {  
        System.Console.WriteLine("Standard transportation.");  
    }  
}  
  
// Define the derived classes.  
  
// Class ConvertibleCar uses the new modifier to acknowledge that ShowDetails  
// hides the base class method.  
class ConvertibleCar : Car  
{  
    public new void ShowDetails()  
    {  
        System.Console.WriteLine("A roof that opens up.");  
    }  
}  
  
// Class Minivan uses the override modifier to specify that ShowDetails  
// extends the base class method.  
class Minivan : Car  
{  
    public override void ShowDetails()  
    {  
        System.Console.WriteLine("Carries seven people.");  
    }  
}  

この例では、どちらのバージョンの ShowDetails が呼び出されるかをテストします。The example tests which version of ShowDetails is called. 次の TestCars1 メソッドでは、各クラスのインスタンスを宣言した後、各インスタンスの DescribeCar を呼び出します。The following method, TestCars1, declares an instance of each class, and then calls DescribeCar on each instance.

public static void TestCars1()  
{  
    System.Console.WriteLine("\nTestCars1");  
    System.Console.WriteLine("----------");  
  
    Car car1 = new Car();  
    car1.DescribeCar();  
    System.Console.WriteLine("----------");  
  
    // Notice the output from this test case. The new modifier is  
    // used in the definition of ShowDetails in the ConvertibleCar  
    // class.    
  
    ConvertibleCar car2 = new ConvertibleCar();  
    car2.DescribeCar();  
    System.Console.WriteLine("----------");  
  
    Minivan car3 = new Minivan();  
    car3.DescribeCar();  
    System.Console.WriteLine("----------");  
}  

TestCars1 で生成される出力は次のとおりです。TestCars1 produces the following output. car2 の結果に特に注目してください。予測していた内容と違っている可能性があります。Notice especially the results for car2, which probably are not what you expected. オブジェクトの型は ConvertibleCar ですが、DescribeCarConvertibleCar クラスで定義されているバージョンの ShowDetails にアクセスしていません。これは、このメソッドが、override 修飾子ではなく new 修飾子を使って宣言されているためです。The type of the object is ConvertibleCar, but DescribeCar does not access the version of ShowDetails that is defined in the ConvertibleCar class because that method is declared with the new modifier, not the override modifier. 結果として、ConvertibleCar オブジェクトでは Car オブジェクトと同じ説明が表示されます。As a result, a ConvertibleCar object displays the same description as a Car object. Minivan オブジェクトである car3 の結果と比べてみてください。Contrast the results for car3, which is a Minivan object. この場合は、Minivan で宣言されている ShowDetails メソッドは、Car クラスで宣言されている ShowDetails メソッドをオーバーライドし、表示されるのはミニバンの説明です。In this case, the ShowDetails method that is declared in the Minivan class overrides the ShowDetails method that is declared in the Car class, and the description that is displayed describes a minivan.

// TestCars1  
// ----------  
// Four wheels and an engine.  
// Standard transportation.  
// ----------  
// Four wheels and an engine.  
// Standard transportation.  
// ----------  
// Four wheels and an engine.  
// Carries seven people.  
// ----------  

TestCars2 は、Car 型のオブジェクトのリストを作成します。TestCars2 creates a list of objects that have type Car. オブジェクトの値は、CarConvertibleCarMinivan の各クラスからインスタンス化されます。The values of the objects are instantiated from the Car, ConvertibleCar, and Minivan classes. DescribeCar は、リストの各要素に対して呼び出されます。DescribeCar is called on each element of the list. 次のコードは、TestCars2 の定義です。The following code shows the definition of TestCars2.

public static void TestCars2()  
{  
    System.Console.WriteLine("\nTestCars2");  
    System.Console.WriteLine("----------");  
  
    var cars = new List<Car> { new Car(), new ConvertibleCar(),   
        new Minivan() };  
  
    foreach (var car in cars)  
    {  
        car.DescribeCar();  
        System.Console.WriteLine("----------");  
    }  
}  

次のような出力が表示されます。The following output is displayed. TestCars1 によって表示される出力と同じであることに注意してください。Notice that it is the same as the output that is displayed by TestCars1. オブジェクトの型が ConvertibleCar であるか (TestCars1 の場合)、Car であるか (TestCars2 の場合) にかかわらず、ConvertibleCar クラスの ShowDetails メソッドは呼び出されません。The ShowDetails method of the ConvertibleCar class is not called, regardless of whether the type of the object is ConvertibleCar, as in TestCars1, or Car, as in TestCars2. 逆に、car3 は、型が Minivan でも Car でも、Minivan クラスの ShowDetails を呼び出します。Conversely, car3 calls the ShowDetails method from the Minivan class in both cases, whether it has type Minivan or type Car.

// TestCars2  
// ----------  
// Four wheels and an engine.  
// Standard transportation.  
// ----------  
// Four wheels and an engine.  
// Standard transportation.  
// ----------  
// Four wheels and an engine.  
// Carries seven people.  
// ----------  

メソッド TestCars3TestCars4 でこの例は終わりです。Methods TestCars3 and TestCars4 complete the example. これらのメソッドは、最初は型 ConvertibleCar および Minivan として宣言されているオブジェクトから (TestCars3)、次に型 Car として宣言されているオブジェクトから (TestCars4)、ShowDetails を直接呼び出します。These methods call ShowDetails directly, first from objects declared to have type ConvertibleCar and Minivan (TestCars3), then from objects declared to have type Car (TestCars4). 次のコードは、これら 2 つのメソッドの定義です。The following code defines these two methods.

public static void TestCars3()  
{  
    System.Console.WriteLine("\nTestCars3");  
    System.Console.WriteLine("----------");  
    ConvertibleCar car2 = new ConvertibleCar();  
    Minivan car3 = new Minivan();  
    car2.ShowDetails();  
    car3.ShowDetails();  
}  
  
public static void TestCars4()  
{  
    System.Console.WriteLine("\nTestCars4");  
    System.Console.WriteLine("----------");  
    Car car2 = new ConvertibleCar();  
    Car car3 = new Minivan();  
    car2.ShowDetails();  
    car3.ShowDetails();  
}  

これらのメソッドからは次のような出力が生成され、これはこのトピックの最初の例からの結果に対応します。The methods produce the following output, which corresponds to the results from the first example in this topic.

// TestCars3  
// ----------  
// A roof that opens up.  
// Carries seven people.  
  
// TestCars4  
// ----------  
// Standard transportation.  
// Carries seven people.  

完全なプロジェクトとその出力を次に示します。The following code shows the complete project and its output.

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;  
  
namespace OverrideAndNew2  
{  
    class Program  
    {  
        static void Main(string[] args)  
        {  
            // Declare objects of the derived classes and test which version  
            // of ShowDetails is run, base or derived.  
            TestCars1();  
  
            // Declare objects of the base class, instantiated with the  
            // derived classes, and repeat the tests.  
            TestCars2();  
  
            // Declare objects of the derived classes and call ShowDetails  
            // directly.  
            TestCars3();  
  
            // Declare objects of the base class, instantiated with the  
            // derived classes, and repeat the tests.  
            TestCars4();  
        }  
  
        public static void TestCars1()  
        {  
            System.Console.WriteLine("\nTestCars1");  
            System.Console.WriteLine("----------");  
  
            Car car1 = new Car();  
            car1.DescribeCar();  
            System.Console.WriteLine("----------");  
  
            // Notice the output from this test case. The new modifier is  
            // used in the definition of ShowDetails in the ConvertibleCar  
            // class.    
            ConvertibleCar car2 = new ConvertibleCar();  
            car2.DescribeCar();  
            System.Console.WriteLine("----------");  
  
            Minivan car3 = new Minivan();  
            car3.DescribeCar();  
            System.Console.WriteLine("----------");  
        }  
        // Output:  
        // TestCars1  
        // ----------  
        // Four wheels and an engine.  
        // Standard transportation.  
        // ----------  
        // Four wheels and an engine.  
        // Standard transportation.  
        // ----------  
        // Four wheels and an engine.  
        // Carries seven people.  
        // ----------  
  
        public static void TestCars2()  
        {  
            System.Console.WriteLine("\nTestCars2");  
            System.Console.WriteLine("----------");  
  
            var cars = new List<Car> { new Car(), new ConvertibleCar(),   
                new Minivan() };  
  
            foreach (var car in cars)  
            {  
                car.DescribeCar();  
                System.Console.WriteLine("----------");  
            }  
        }  
        // Output:  
        // TestCars2  
        // ----------  
        // Four wheels and an engine.  
        // Standard transportation.  
        // ----------  
        // Four wheels and an engine.  
        // Standard transportation.  
        // ----------  
        // Four wheels and an engine.  
        // Carries seven people.  
        // ----------  
  
        public static void TestCars3()  
        {  
            System.Console.WriteLine("\nTestCars3");  
            System.Console.WriteLine("----------");  
            ConvertibleCar car2 = new ConvertibleCar();  
            Minivan car3 = new Minivan();  
            car2.ShowDetails();  
            car3.ShowDetails();  
        }  
        // Output:  
        // TestCars3  
        // ----------  
        // A roof that opens up.  
        // Carries seven people.  
  
        public static void TestCars4()  
        {  
            System.Console.WriteLine("\nTestCars4");  
            System.Console.WriteLine("----------");  
            Car car2 = new ConvertibleCar();  
            Car car3 = new Minivan();  
            car2.ShowDetails();  
            car3.ShowDetails();  
        }  
        // Output:  
        // TestCars4  
        // ----------  
        // Standard transportation.  
        // Carries seven people.  
    }  
  
    // Define the base class, Car. The class defines two virtual methods,  
    // DescribeCar and ShowDetails. DescribeCar calls ShowDetails, and each derived  
    // class also defines a ShowDetails method. The example tests which version of  
    // ShowDetails is used, the base class method or the derived class method.  
    class Car  
    {  
        public virtual void DescribeCar()  
        {  
            System.Console.WriteLine("Four wheels and an engine.");  
            ShowDetails();  
        }  
  
        public virtual void ShowDetails()  
        {  
            System.Console.WriteLine("Standard transportation.");  
        }  
    }  
  
    // Define the derived classes.  
  
    // Class ConvertibleCar uses the new modifier to acknowledge that ShowDetails  
    // hides the base class method.  
    class ConvertibleCar : Car  
    {  
        public new void ShowDetails()  
        {  
            System.Console.WriteLine("A roof that opens up.");  
        }  
    }  
  
    // Class Minivan uses the override modifier to specify that ShowDetails  
    // extends the base class method.  
    class Minivan : Car  
    {  
        public override void ShowDetails()  
        {  
            System.Console.WriteLine("Carries seven people.");  
        }  
    }  
  
}  

関連項目See also