다음을 통해 공유


재정의 및 새 키워드를 사용해야 하는 경우 파악(C# 프로그래밍 가이드)

C#에서 파생 클래스의 메서드는 기본 클래스의 메서드와 동일한 이름을 가질 수 있습니다. new 키워드와 재정의 키워드를 사용하여 메서드의 상호 작용 방식을 지정할 수 있습니다. override 한정자는 기본 클래스 메서드virtualnew 정자는 액세스 가능한 기본 클래스 메서드를 숨깁니다. 차이점은 이 항목의 예제에 설명되어 있습니다.

콘솔 애플리케이션에서 다음 두 클래스를 선언합니다BaseClass. DerivedClass 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입니다. 이 변수는 주의해야 할 변수입니다.

bcbcdcBaseClass 유형이므로, 캐스팅을 사용하지 않으면 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. 이 메서드의 서명은 Method2DerivedClass 메서드 서명과 일치합니다.

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

이제 BaseClassMethod2 메서드가 있기 때문에 아래 코드에 표시된 것처럼 BaseClassbc 변수에 대해 bcdc 두 번째 호출 문을 추가할 수 있습니다.

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

프로젝트를 빌드할 때, Method2BaseClass 메서드를 추가하면 경고가 발생한다. 경고는 Method2DerivedClass 메서드가 Method2에서 BaseClass 메서드를 숨긴다고 합니다. new 정의에서 Method2 키워드를 사용하려는 경우에는 해당 결과를 발생시키기 위해 그렇게 하도록 권장됩니다. 또는 경고를 해결하기 위해 메서드 중 Method2 하나의 이름을 바꿀 수 있지만 항상 실용적인 것은 아닙니다.

추가 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");  
}  

프로젝트를 다시 실행합니다. 특히 다음 출력의 마지막 두 줄을 확인합니다.

// 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 클래스에서 파생된 두 개의 클래스를 ConvertibleCar 정의합니다 Minivan. 기본 클래스에는 메서드가 포함되어 있습니다 DescribeCar . 메서드는 자동차에 대한 기본 설명을 표시한 다음 추가 정보를 제공하기 위해 호출 ShowDetails 합니다. 세 클래스는 각각 메서드를 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이지만, DescribeCarShowDetails 클래스에 정의된 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 클래스의 메서드는 개체ConvertibleCarConvertibleCar 형식에 관계 없이 호출 되지 않습니다.TestCars1CarTestCars2 반대로, 두 경우 모두 car3ShowDetails 클래스의 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 예제를 완료합니다. 이러한 메서드는 우선 형식 ShowDetailsConvertibleCar (Minivan)으로 선언된 개체에서 TestCars3을 직접 호출하고, 그런 다음 형식 Car (TestCars4)으로 선언된 개체에서 호출합니다. 다음 코드는 이러한 두 가지 메서드를 정의합니다.

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.");  
        }  
    }  
  
}  

참고하십시오