C# では、派生クラスのメソッドは基底クラスのメソッドと同じ名前を持つことができます。
新しいキーワードとオーバーライド キーワードを使用して、メソッドの対話方法を指定できます。
override
修飾子は基底クラスメソッドをvirtual
し、new
修飾子はアクセス可能な基底クラス メソッドを非表示にします。 このトピックの例では、違いを示します。
コンソール アプリケーションで、 BaseClass
と DerivedClass
の 2 つのクラスを宣言します。
DerivedClass
は、BaseClass
から継承されます。
class BaseClass
{
public void Method1()
{
Console.WriteLine("Base - Method1");
}
}
class DerivedClass : BaseClass
{
public void Method2()
{
Console.WriteLine("Derived - Method2");
}
}
Main
メソッドで、変数bc
、dc
、およびbcdc
を宣言します。
bc
はBaseClass
型であり、その値はBaseClass
型です。dc
はDerivedClass
型であり、その値はDerivedClass
型です。bcdc
はBaseClass
型であり、その値はDerivedClass
型です。 これは注意を払う変数です。
bc
とbcdc
には型BaseClass
があるため、キャストを使用しない限り、Method1
にのみ直接アクセスできます。 変数 dc
は、 Method1
と Method2
の両方にアクセスできます。 これらのリレーションシップを次のコードに示します。
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
に追加します。 このメソッドのシグネチャは、Method2
のDerivedClass
メソッドのシグネチャと一致します。
public void Method2()
{
Console.WriteLine("Base - Method2");
}
BaseClass
には Method2
メソッドがあるため、次のコードに示すように、BaseClass
変数のbc
とbcdc
に対して 2 つ目の呼び出しステートメントを追加できます。
bc.Method1();
bc.Method2();
dc.Method1();
dc.Method2();
bcdc.Method1();
bcdc.Method2();
プロジェクトをビルドすると、Method2
に BaseClass
メソッドを追加すると警告が発生することがわかります。 警告は、Method2
のDerivedClass
メソッドがMethod2
のBaseClass
メソッドを非表示にすることを示しています。 その結果を発生させる場合は、new
定義で Method2
キーワードを使用することをお勧めします。 または、警告を解決するために Method2
メソッドの 1 つの名前を変更することもできますが、必ずしも実用的であるとは限りません。
new
を追加する前に、プログラムを実行して、追加の呼び出し元ステートメントによって生成された出力を確認します。 次の結果が表示されます。
// Output:
// Base - Method1
// Base - Method2
// Base - Method1
// Derived - Method2
// Base - Method1
// Base - Method2
new
キーワードは、その出力を生成するリレーションシップを保持しますが、警告は抑制されます。 型 BaseClass
を持つ変数は BaseClass
のメンバーに引き続きアクセスし、型 DerivedClass
を持つ変数は、最初に DerivedClass
のメンバーにアクセスし続け、 BaseClass
から継承されたメンバーを考慮します。
警告を抑制するには、次のコードに示すように、new
のMethod2
の定義にDerivedClass
修飾子を追加します。 修飾子は、 public
の前または後に追加できます。
public new void Method2()
{
Console.WriteLine("Derived - Method2");
}
プログラムをもう一度実行して、出力が変更されていないことを確認します。 また、警告が表示されなくなったことを確認します。
new
を使用すると、変更されたメンバーが基底クラスから継承されたメンバーを非表示にすることを認識していることをアサートします。 継承による名前の非表示の詳細については、「 新しい修飾子」を参照してください。
この動作と override
の使用による影響を比較するには、次のメソッドを DerivedClass
に追加します。
override
修飾子は、public
の前または後に追加できます。
public override void Method1()
{
Console.WriteLine("Derived - Method1");
}
virtual
のMethod1
の定義にBaseClass
修飾子を追加します。
virtual
修飾子は、public
の前または後に追加できます。
public virtual void Method1()
{
Console.WriteLine("Base - Method1");
}
プロジェクトをもう一度実行します。 特に、次の出力の最後の 2 行に注目してください。
// Output:
// Base - Method1
// Base - Method2
// Derived - Method1
// Derived - Method2
// Derived - Method1
// Base - Method2
override
修飾子を使用すると、bcdc
は、Method1
で定義されているDerivedClass
メソッドにアクセスできます。 通常、これは継承階層で必要な動作です。 派生クラスから作成された値を持つオブジェクトで、派生クラスで定義されているメソッドを使用する必要があります。 この動作を実現するには、 override
を使用して基底クラス メソッドを拡張します。
次のコードには、完全な例が含まれています。
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");
}
}
}
次の例は、別のコンテキストでの同様の動作を示しています。 この例では、 Car
という名前の基底クラスと、そこから派生した 2 つのクラス ( ConvertibleCar
と Minivan
) の 3 つのクラスを定義します。 基底クラスには、 DescribeCar
メソッドが含まれています。 このメソッドは車の基本的な説明を表示し、 ShowDetails
を呼び出して追加情報を提供します。 3 つのクラスはそれぞれ、 ShowDetails
メソッドを定義します。
new
修飾子は、ShowDetails
クラスでConvertibleCar
を定義するために使用されます。
override
修飾子は、ShowDetails
クラスでMinivan
を定義するために使用されます。
// 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
のバージョンをテストします。 次のメソッド TestCars1
、各クラスのインスタンスを宣言し、各インスタンスで DescribeCar
を呼び出します。
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
は次の出力を生成します。 特に car2
の結果に注目してください。これは、おそらく期待した結果ではありません。 オブジェクトの型はConvertibleCar
ですが、DescribeCar
ShowDetails
クラスで定義されているConvertibleCar
のバージョンにはアクセスできません。これは、そのメソッドがnew
修飾子ではなく、override
修飾子で宣言されているためです。 その結果、 ConvertibleCar
オブジェクトには、 Car
オブジェクトと同じ説明が表示されます。
car3
オブジェクトであるMinivan
の結果を比較します。 この場合、ShowDetails
クラスで宣言されているMinivan
メソッドは、ShowDetails
クラスで宣言されているCar
メソッドをオーバーライドし、表示される説明では、ミニバンについて説明します。
// 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
オブジェクトの一覧を作成します。 オブジェクトの値は、 Car
、 ConvertibleCar
、および Minivan
クラスからインスタンス化されます。
DescribeCar
は、リストの各要素で呼び出されます。 次のコードは、 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("----------");
}
}
次の出力が表示されます。
TestCars1
によって表示される出力と同じであることに注意してください。
ShowDetails
クラスのConvertibleCar
メソッドは、ConvertibleCar
のように、オブジェクトの型がTestCars1
とCar
のどちらでTestCars2
されているかに関係なく呼び出されません。 逆に、car3
はどちらの場合も、ShowDetails
クラスからMinivan
メソッドを呼び出します(型Minivan
か型Car
か)。
// TestCars2
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Carries seven people.
// ----------
メソッド TestCars3
および TestCars4
は例を完成します。 これらのメソッドは ShowDetails
を直接呼び出し、最初に型 ConvertibleCar
と Minivan
(TestCars3
) を持つ宣言されたオブジェクトから、次に型 Car
(TestCars4
) を持つ宣言されたオブジェクトから呼び出します。 次のコードでは、これら 2 つのメソッドを定義します。
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();
}
メソッドは、このトピックの最初の例の結果に対応する次の出力を生成します。
// TestCars3
// ----------
// A roof that opens up.
// Carries seven people.
// TestCars4
// ----------
// Standard transportation.
// Carries seven people.
次のコードは、プロジェクト全体とその出力を示しています。
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.");
}
}
}
こちらも参照ください
.NET