Nice programing

메서드 숨기기와 재정의

nicepro 2021. 1. 9. 11:38
반응형

메서드 숨기기와 재정의


이 질문에 이미 답변이 있습니다.

C #에서 메서드를 재정의하는 것과 숨기는 것에 대해 약간 혼란 스럽습니다. 각각의 실제적인 사용과 각각의 사용시기에 대한 설명도 감사 것입니다.

재정의에 대해 혼란 스럽습니다. 왜 재정의해야합니까? 지금까지 내가 배운 것은 오버 링을 통해 서명을 변경하지 않고도 파생 클래스의 메서드에 원하는 구현을 제공 할 수 있다는 것입니다.

수퍼 클래스의 메서드를 재정의하지 않고 하위 클래스의 메서드를 변경하면 수퍼 클래스 메서드가 변경됩니까?

나는 또한 다음에 대해 혼란 스럽습니다. 이것은 무엇을 증명합니까?

class A
{
    virtual m1()
    {
        console.writeline("Bye to all");
    }
}

class B : A
{
    override m1()
    {
        console.writeLine("Hi to all");
    }
}

class C
{
    A a = new A();
    B b = new B();
    a = b; (what is this)
    a.m1(); // what this will print and why?

    b = a; // what happens here?
}

중히 여기다:

public class BaseClass
{
  public void WriteNum()
  {
    Console.WriteLine(12);
  }
  public virtual void WriteStr()
  {
    Console.WriteLine("abc");
  }
}

public class DerivedClass : BaseClass
{
  public new void WriteNum()
  {
    Console.WriteLine(42);
  }
  public override void WriteStr()
  {
    Console.WriteLine("xyz");
  }
}
/* ... */
BaseClass isReallyBase = new BaseClass();
BaseClass isReallyDerived = new DerivedClass();
DerivedClass isClearlyDerived = new DerivedClass();

isReallyBase.WriteNum(); // writes 12
isReallyBase.WriteStr(); // writes abc
isReallyDerived.WriteNum(); // writes 12
isReallyDerived.WriteStr(); // writes xyz
isClearlyDerived.WriteNum(); // writes 42
isClearlyDerived.writeStr(); // writes xyz

재정의는 파생 클래스가 기본 클래스보다 더 구체적인 동작을 가질 수있는 고전적인 OO 방식입니다 (일부 언어에서는 선택의 여지가 없음). 객체에서 가상 메서드가 호출되면 가장 많이 파생 된 메서드 버전이 호출됩니다. 따라서 우리가 다루고있는 경우에도 isReallyDerivedA와 BaseClass정의 다음 기능이 DerivedClass사용됩니다.

숨기는 것은 우리가 완전히 다른 방법을 가지고 있다는 것을 의미합니다. 우리가 호출하는 경우 WriteNum()isReallyDerived다음 다른이 있음을 알 수있는 방법은 없습니다 WriteNum()DerivedClass가 호출되지 않도록이. 우리가 객체를 처리 할 때 그것은 단지 호출 할 수 있습니다 DerivedClass .

Most of the time hiding is bad. Generally, either you should have a method as virtual if its likely to be changed in a derived class, and override it in the derived class. There are however two things it is useful for:

  1. Forward compatibility. If DerivedClass had a DoStuff() method, and then later on BaseClass was changed to add a DoStuff() method, (remember that they may be written by different people and exist in different assemblies) then a ban on member hiding would have suddenly made DerivedClass buggy without it changing. Also, if the new DoStuff() on BaseClass was virtual, then automatically making that on DerivedClass an override of it could lead to the pre-existing method being called when it shouldn't. Hence it's good that hiding is the default (we use new to make it clear we definitely want to hide, but leaving it out hides and emits a warning on compilation).

  2. Poor-man's covariance. Consider a Clone() method on BaseClass that returns a new BaseClass that's a copy of that created. In the override on DerivedClass this will create a DerivedClass but return it as a BaseClass, which isn't as useful. What we could do is to have a virtual protected CreateClone() that is overridden. In BaseClass we have a Clone() that returns the result of this - and all is well - in DerivedClass we hide this with a new Clone() that returns a DerivedClass. Calling Clone() on BaseClass will always return a BaseClass reference, which will be a BaseClass value or a DerivedClass value as appropriate. Calling Clone() on DerivedClass will return a DerivedClass value, which is what we'd want in that context. There are other variants of this principle, however it should be noted that they are all pretty rare.

An important thing to note with the second case, is that we've used hiding precisely to remove surprises to the calling code, as the person using DerivedClass might reasonably expect its Clone() to return a DerivedClass. The results of any of the ways it could be called are kept consistent with each other. Most cases of hiding risk introducing surprises, which is why they are generally frowned upon. This one is justified precisely because it solves the very problem that hiding often introduces.

In all, hiding is sometimes necessary, infrequently useful, but generally bad, so be very wary of it.


Overriding is when you provide a new override implementation of a method in a descendant class when that method is defined in the base class as virtual.

Hiding is when you provide a new implementation of a method in a descendant class when that method is not defined in the base class as virtual, or when your new implementation does not specify override.

Hiding is very often bad; you should generally try not to do it if you can avoid it at all. Hiding can cause unexpected things to happen, because Hidden methods are only used when called on a variable of the actual type you defined, not if using a base class reference... on the other hand, Virtual methods which are overridden will end up with the proper method version being called, even when called using the base class reference on a child class.

For instance, consider these classes:

public class BaseClass
{
  public virtual void Method1()  //Virtual method
  {
    Console.WriteLine("Running BaseClass Method1");
  }
  public void Method2()  //Not a virtual method
  {
    Console.WriteLine("Running BaseClass Method2");
  }
}
public class InheritedClass : BaseClass
{
  public override void Method1()  //Overriding the base virtual method.
  {
    Console.WriteLine("Running InheritedClass Method1");
  }
  public new void Method2()  //Can't override the base method; must 'new' it.
  {
    Console.WriteLine("Running InheritedClass Method2");
  }
}

Let's call it like this, with an instance of InheritedClass, in a matching reference:

InheritedClass inherited = new InheritedClass();
inherited.Method1();
inherited.Method2();

This returns what you should expect; both methods say they are running the InheritedClass versions.

Running InheritedClass Method1
Running InheritedClass Method2

This code creates an instance of the same, InheritedClass, but stores it in a BaseClass reference:

BaseClass baseRef = new InheritedClass();
baseRef.Method1();
baseRef.Method2();

Normally, under OOP principles, you should expect the same output as the above example. But you don't get the same output:

Running InheritedClass Method1
Running BaseClass Method2

When you wrote the InheritedClass code, you may have wanted all calls to Method2() to run the code you wrote in it. Normally, this would be how it works - assuming you are working with a virtual method that you have overridden. But because you are using a new/hidden method, it calls the version on the reference you are using, instead.


If that's the behavior you truly want, then; there you go. But I would strongly suggest that if that's what you want, there may be a larger architectural issue with the code.


Method Overriding is simpley override a default implementation of a base class method in the derived class.

Method Hiding : You can make use of 'new' keyword before a virtual method in a derived class

as

class Foo  
{  
  public virtual void foo1()  
  {  

  }  
}  

class Bar:Foo  
{  
  public new virtual void foo1()  
  {   

  }  
}  

now if you make another class Bar1 which is derived from Bar , you can override foo1 which is defind in Bar.

ReferenceURL : https://stackoverflow.com/questions/3838553/overriding-vs-method-hiding

반응형